NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
+
+* Portions of internationalization code use code or data from Unicode, which
+ carry the following license:
+
+ UNICODE, INC. LICENSE AGREEMENT - DATA FILES AND SOFTWARE
+
+ See Terms of Use <https://www.unicode.org/copyright.html>
+ for definitions of Unicode Inc.’s Data Files and Software.
+
+ NOTICE TO USER: Carefully read the following legal agreement.
+ BY DOWNLOADING, INSTALLING, COPYING OR OTHERWISE USING UNICODE INC.'S
+ DATA FILES ("DATA FILES"), AND/OR SOFTWARE ("SOFTWARE"),
+ YOU UNEQUIVOCALLY ACCEPT, AND AGREE TO BE BOUND BY, ALL OF THE
+ TERMS AND CONDITIONS OF THIS AGREEMENT.
+ IF YOU DO NOT AGREE, DO NOT DOWNLOAD, INSTALL, COPY, DISTRIBUTE OR USE
+ THE DATA FILES OR SOFTWARE.
+
+ COPYRIGHT AND PERMISSION NOTICE
+
+ Copyright © 1991-2022 Unicode, Inc. All rights reserved.
+ Distributed under the Terms of Use in https://www.unicode.org/copyright.html.
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of the Unicode data files and any associated documentation
+ (the "Data Files") or Unicode software and any associated documentation
+ (the "Software") to deal in the Data Files or Software
+ without restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, and/or sell copies of
+ the Data Files or Software, and to permit persons to whom the Data Files
+ or Software are furnished to do so, provided that either
+ (a) this copyright and permission notice appear with all copies
+ of the Data Files or Software, or
+ (b) this copyright and permission notice appear in associated
+ Documentation.
+
+ THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF
+ ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+ WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT OF THIRD PARTY RIGHTS.
+ IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS
+ NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL
+ DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ PERFORMANCE OF THE DATA FILES OR SOFTWARE.
+
+ Except as contained in this notice, the name of a copyright holder
+ shall not be used in advertising or otherwise to promote the sale,
+ use or other dealings in these Data Files or Software without prior
+ written authorization of the copyright holder.
[[package]]
name = "addr2line"
-version = "0.16.0"
+version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd"
+checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
dependencies = [
"compiler_builtins",
- "gimli 0.25.0",
+ "gimli",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
]
-[[package]]
-name = "addr2line"
-version = "0.17.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
-dependencies = [
- "gimli 0.26.1",
-]
-
[[package]]
name = "adler"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-core",
-]
[[package]]
name = "adler"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+dependencies = [
+ "compiler_builtins",
+ "rustc-std-workspace-core",
+]
[[package]]
name = "ahash"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cab84319d616cfb654d03394f38ab7e6f0919e181b1b57e1fd15e7fb4077d9a7"
dependencies = [
- "addr2line 0.17.0",
+ "addr2line",
"cc",
"cfg-if 1.0.0",
"libc",
"miniz_oxide 0.5.3",
- "object 0.29.0",
+ "object",
"rustc-demangle",
]
"glob",
"itertools",
"lazy_static",
- "remove_dir_all",
"serde_json",
"snapbox",
"tar",
"jobserver",
"libc",
"log",
- "miow",
+ "miow 0.4.0",
"same-file",
"shell-escape",
"tempfile",
"lazy_static",
"lazycell",
"libc",
- "miow",
+ "miow 0.3.7",
+ "miropt-test-tools",
"regex",
"rustfix",
"serde",
"lazy_static",
"libc",
"log",
- "miow",
+ "miow 0.3.7",
"regex",
"rustfix",
"serde",
[[package]]
name = "concolor"
-version = "0.0.8"
+version = "0.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "015267563b1df20adccdd00cb05257b1dfbea70a04928e9cf88ffb850c1a40af"
+checksum = "b90f9dcd9490a97db91a85ccd79e38a87e14323f0bb824659ee3274e9143ba37"
dependencies = [
"atty",
"bitflags",
[[package]]
name = "concolor-query"
-version = "0.0.5"
+version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6417fe6fc03a8b533fd2177742eeb39a90c7233eedec7bac96d4d6b69a09449"
+checksum = "82a90734b3d5dcf656e7624cca6bce9c3a90ee11f900e80141a7427ccfb3d317"
[[package]]
name = "content_inspector"
[[package]]
name = "curl"
-version = "0.4.43"
+version = "0.4.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37d855aeef205b43f65a5001e0997d81f8efca7badad4fad7d897aa7f0d0651f"
+checksum = "509bd11746c7ac09ebd19f0b17782eae80aadee26237658a6b4808afb5c11a22"
dependencies = [
"curl-sys",
"libc",
[[package]]
name = "curl-sys"
-version = "0.4.55+curl-7.83.1"
+version = "0.4.59+curl-7.86.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23734ec77368ec583c2e61dd3f0b0e5c98b93abe6d2a004ca06b91dd7e3e2762"
+checksum = "6cfce34829f448b08f55b7db6d0009e23e2e86a34e8c2b366269bf5799b4a407"
dependencies = [
"cc",
"libc",
"winapi",
]
+[[package]]
+name = "displaydoc"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3bf95dc3f046b9da4f2d51833c0d3547d8564ef6910f5c1ed130306a75b92886"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
[[package]]
name = "dlmalloc"
version = "0.2.3"
[[package]]
name = "getrandom"
-version = "0.1.14"
+version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb"
+checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
dependencies = [
- "cfg-if 0.1.10",
+ "cfg-if 1.0.0",
"libc",
"wasi 0.9.0+wasi-snapshot-preview1",
]
"wasi 0.9.0+wasi-snapshot-preview1",
]
-[[package]]
-name = "gimli"
-version = "0.25.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7"
-dependencies = [
- "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
[[package]]
name = "gimli"
version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4"
dependencies = [
+ "compiler_builtins",
"fallible-iterator",
"indexmap",
+ "rustc-std-workspace-alloc",
+ "rustc-std-workspace-core",
"stable_deref_trait",
]
[[package]]
name = "intl_pluralrules"
-version = "7.0.1"
+version = "7.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b18f988384267d7066cc2be425e6faf352900652c046b6971d2e228d3b1c5ecf"
+checksum = "078ea7b7c29a2b4df841a7f6ac8775ff6074020c6776d48491ce2268e068f972"
dependencies = [
- "tinystr",
"unic-langid",
]
checksum = "be0f75932c1f6cfae3c04000e40114adf955636e19040f9c0a2c380702aa1c7f"
dependencies = [
"adler 0.2.3",
- "compiler_builtins",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
]
[[package]]
checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc"
dependencies = [
"adler 1.0.2",
+ "compiler_builtins",
+ "rustc-std-workspace-alloc",
+ "rustc-std-workspace-core",
]
[[package]]
"winapi",
]
+[[package]]
+name = "miow"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7377f7792b3afb6a3cba68daa54ca23c032137010460d667fda53a8d66be00e"
+dependencies = [
+ "windows-sys 0.28.0",
+]
+
[[package]]
name = "miri"
version = "0.1.0"
"ui_test",
]
+[[package]]
+name = "miropt-test-tools"
+version = "0.1.0"
+dependencies = [
+ "regex",
+]
+
[[package]]
name = "new_debug_unreachable"
version = "1.0.4"
"libc",
]
-[[package]]
-name = "object"
-version = "0.26.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2"
-dependencies = [
- "compiler_builtins",
- "memchr",
- "rustc-std-workspace-alloc",
- "rustc-std-workspace-core",
-]
-
[[package]]
name = "object"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
dependencies = [
+ "compiler_builtins",
"crc32fast",
"flate2",
"hashbrown",
"indexmap",
"memchr",
+ "rustc-std-workspace-alloc",
+ "rustc-std-workspace-core",
]
[[package]]
version = "0.0.0"
dependencies = [
"alloc",
- "cfg-if 0.1.10",
+ "cfg-if 1.0.0",
"compiler_builtins",
"core",
"libc",
version = "0.0.0"
dependencies = [
"alloc",
- "cfg-if 0.1.10",
+ "cfg-if 1.0.0",
"compiler_builtins",
"core",
"libc",
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
- "parking_lot_core 0.9.3",
+ "parking_lot_core 0.9.4",
]
[[package]]
[[package]]
name = "parking_lot_core"
-version = "0.9.3"
+version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929"
+checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0"
dependencies = [
"cfg-if 1.0.0",
"libc",
"redox_syscall",
"smallvec",
- "windows-sys",
+ "windows-sys 0.42.0",
]
[[package]]
[[package]]
name = "psm"
-version = "0.1.16"
+version = "0.1.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd136ff4382c4753fc061cb9e4712ab2af263376b95bbd5bd8cd50c020b78e69"
+checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874"
dependencies = [
"cc",
]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
dependencies = [
- "getrandom 0.1.14",
+ "getrandom 0.1.16",
"libc",
"rand_chacha 0.2.2",
"rand_core 0.5.1",
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
dependencies = [
- "getrandom 0.1.14",
+ "getrandom 0.1.16",
]
[[package]]
"cstr",
"libc",
"measureme",
- "object 0.29.0",
+ "object",
"rustc-demangle",
"rustc_ast",
"rustc_attr",
"itertools",
"jobserver",
"libc",
- "object 0.29.0",
+ "object",
"pathdiff",
"regex",
"rustc_arena",
name = "rustc_interface"
version = "0.0.0"
dependencies = [
- "libc",
"libloading",
"rustc-rayon",
"rustc-rayon-core",
"rustc_ty_utils",
"smallvec",
"tracing",
- "winapi",
]
[[package]]
version = "0.0.0"
dependencies = [
"getopts",
+ "libc",
"rustc_ast",
"rustc_data_structures",
"rustc_errors",
"rustc_serialize",
"rustc_span",
"rustc_target",
+ "smallvec",
"tracing",
+ "winapi",
]
[[package]]
[[package]]
name = "snapbox"
-version = "0.3.3"
+version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44d199ccf8f606592df2d145db26f2aa45344e23c64b074cc5a4047f1d99b0f7"
+checksum = "827c00e91b15e2674d8a5270bae91f898693cbf9561cbb58d8eaa31974597293"
dependencies = [
"concolor",
"content_inspector",
[[package]]
name = "stacker"
-version = "0.1.14"
+version = "0.1.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90939d5171a4420b3ff5fbc8954d641e7377335454c259dcb80786f3f21dc9b4"
+checksum = "c886bd4480155fd3ef527d45e9ac8dd7118a898a46530b7b94c3e21866259fce"
dependencies = [
"cc",
"cfg-if 1.0.0",
name = "std"
version = "0.0.0"
dependencies = [
- "addr2line 0.16.0",
+ "addr2line",
"alloc",
"cfg-if 1.0.0",
"compiler_builtins",
"hashbrown",
"hermit-abi 0.2.6",
"libc",
- "miniz_oxide 0.4.0",
- "object 0.26.2",
+ "miniz_oxide 0.5.3",
+ "object",
"panic_abort",
"panic_unwind",
"profiler_builtins",
[[package]]
name = "thin-vec"
-version = "0.2.8"
+version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "104c2cb3180b6fb6d5b2278768e9b88b578d32ba751ea6e8d026688a40d7ed87"
+checksum = "ceb05e71730d396f960f8f3901cdb41be2d339b303e9d7d3a07c5ff0536e671b"
[[package]]
name = "thiserror"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6cb0c7868d7f90407531108ab03263d9452a8811b7cdd87675343a40d4aa254"
dependencies = [
- "gimli 0.26.1",
+ "gimli",
"hashbrown",
- "object 0.29.0",
+ "object",
"tracing",
]
version = "0.1.0"
dependencies = [
"cargo_metadata 0.14.0",
+ "ignore",
"lazy_static",
+ "miropt-test-tools",
"regex",
"walkdir",
]
[[package]]
name = "tinystr"
-version = "0.3.4"
+version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29738eedb4388d9ea620eeab9384884fc3f06f586a2eddb56bedc5885126c7c1"
+checksum = "f8aeafdfd935e4a7fe16a91ab711fa52d54df84f9c8f7ca5837a9d1d902ef4c2"
+dependencies = [
+ "displaydoc",
+]
[[package]]
name = "tinyvec"
[[package]]
name = "unic-langid"
-version = "0.9.0"
+version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73328fcd730a030bdb19ddf23e192187a6b01cd98be6d3140622a89129459ce5"
+checksum = "398f9ad7239db44fd0f80fe068d12ff22d78354080332a5077dc6f52f14dcf2f"
dependencies = [
"unic-langid-impl",
"unic-langid-macros",
[[package]]
name = "unic-langid-impl"
-version = "0.9.0"
+version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a4a8eeaf0494862c1404c95ec2f4c33a2acff5076f64314b465e3ddae1b934d"
+checksum = "e35bfd2f2b8796545b55d7d3fd3e89a0613f68a0d1c8bc28cb7ff96b411a35ff"
dependencies = [
"tinystr",
]
[[package]]
name = "unic-langid-macros"
-version = "0.9.0"
+version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18f980d6d87e8805f2836d64b4138cc95aa7986fa63b1f51f67d5fbff64dd6e5"
+checksum = "055e618bf694161ffff0466d95cef3e1a5edc59f6ba1888e97801f2b4ebdc4fe"
dependencies = [
"proc-macro-hack",
"tinystr",
[[package]]
name = "unic-langid-macros-impl"
-version = "0.9.0"
+version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29396ffd97e27574c3e01368b1a64267d3064969e4848e2e130ff668be9daa9f"
+checksum = "1f5cdec05b907f4e2f6843f4354f4ce6a5bebe1a56df320a49134944477ce4d8"
dependencies = [
"proc-macro-hack",
"quote",
version = "0.0.0"
dependencies = [
"cc",
- "cfg-if 0.1.10",
+ "cfg-if 1.0.0",
"compiler_builtins",
"core",
"libc",
[[package]]
name = "windows-sys"
-version = "0.36.1"
+version = "0.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82ca39602d5cbfa692c4b67e3bcbb2751477355141c1ed434c94da4186836ff6"
+dependencies = [
+ "windows_aarch64_msvc 0.28.0",
+ "windows_i686_gnu 0.28.0",
+ "windows_i686_msvc 0.28.0",
+ "windows_x86_64_gnu 0.28.0",
+ "windows_x86_64_msvc 0.28.0",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
+checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
dependencies = [
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_msvc",
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc 0.42.0",
+ "windows_i686_gnu 0.42.0",
+ "windows_i686_msvc 0.42.0",
+ "windows_x86_64_gnu 0.42.0",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc 0.42.0",
]
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
+
[[package]]
name = "windows_aarch64_msvc"
-version = "0.36.1"
+version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
+checksum = "52695a41e536859d5308cc613b4a022261a274390b25bd29dfff4bf08505f3c2"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
[[package]]
name = "windows_i686_gnu"
-version = "0.36.1"
+version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
+checksum = "f54725ac23affef038fecb177de6c9bf065787c2f432f79e3c373da92f3e1d8a"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
[[package]]
name = "windows_i686_msvc"
-version = "0.36.1"
+version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
+checksum = "51d5158a43cc43623c0729d1ad6647e62fa384a3d135fd15108d37c683461f64"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
[[package]]
name = "windows_x86_64_gnu"
-version = "0.36.1"
+version = "0.28.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc31f409f565611535130cfe7ee8e6655d3fa99c1c61013981e491921b5ce954"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
+checksum = "3f2b8c7cbd3bfdddd9ab98769f9746a7fad1bca236554cd032b78d768bc0e89f"
[[package]]
name = "windows_x86_64_msvc"
-version = "0.36.1"
+version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
+checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
[[package]]
name = "xattr"
"src/tools/error_index_generator",
"src/tools/linkchecker",
"src/tools/lint-docs",
+ "src/tools/miropt-test-tools",
"src/tools/rustbook",
"src/tools/unstable-book-gen",
"src/tools/tidy",
+Version 1.65.0 (2022-11-03)
+==========================
+
+Language
+--------
+- [Error on `as` casts of enums with `#[non_exhaustive]` variants](https://github.com/rust-lang/rust/pull/92744/)
+- [Stabilize `let else`](https://github.com/rust-lang/rust/pull/93628/)
+- [Stabilize generic associated types (GATs)](https://github.com/rust-lang/rust/pull/96709/)
+- [Add lints `let_underscore_drop` and `let_underscore_lock` from Clippy](https://github.com/rust-lang/rust/pull/97739/)
+- [Stabilize `break`ing from arbitrary labeled blocks ("label-break-value")](https://github.com/rust-lang/rust/pull/99332/)
+- [Uninitialized integers, floats, and raw pointers are now considered immediate UB](https://github.com/rust-lang/rust/pull/98919/).
+ Usage of `MaybeUninit` is the correct way to work with uninitialized memory.
+- [Stabilize raw-dylib for Windows x86_64, aarch64, and thumbv7a](https://github.com/rust-lang/rust/pull/99916/)
+- [Do not allow `Drop` impl on foreign ADTs](https://github.com/rust-lang/rust/pull/99576/)
+
+Compiler
+--------
+- [Stabilize -Csplit-debuginfo on Linux](https://github.com/rust-lang/rust/pull/98051/)
+- [Use niche-filling optimization even when multiple variants have data](https://github.com/rust-lang/rust/pull/94075/)
+- [Associated type projections are now verified to be well-formed prior to resolving the underlying type](https://github.com/rust-lang/rust/pull/99217/#issuecomment-1209365630)
+- [Stringify non-shorthand visibility correctly](https://github.com/rust-lang/rust/pull/100350/)
+- [Normalize struct field types when unsizing](https://github.com/rust-lang/rust/pull/101831/)
+- [Update to LLVM 15](https://github.com/rust-lang/rust/pull/99464/)
+- [Fix aarch64 call abi to correctly zeroext when needed](https://github.com/rust-lang/rust/pull/97800/)
+- [debuginfo: Generalize C++-like encoding for enums](https://github.com/rust-lang/rust/pull/98393/)
+- [Add `special_module_name` lint](https://github.com/rust-lang/rust/pull/94467/)
+- [Add support for generating unique profraw files by default when using `-C instrument-coverage`](https://github.com/rust-lang/rust/pull/100384/)
+- [Allow dynamic linking for iOS/tvOS targets](https://github.com/rust-lang/rust/pull/100636/)
+
+New targets:
+
+- [Add armv4t-none-eabi as a tier 3 target](https://github.com/rust-lang/rust/pull/100244/)
+- [Add powerpc64-unknown-openbsd and riscv64-unknown-openbsd as tier 3 targets](https://github.com/rust-lang/rust/pull/101025/)
+ - Refer to Rust's [platform support page][platform-support-doc] for more
+ information on Rust's tiered platform support.
+
+Libraries
+---------
+
+- [Don't generate `PartialEq::ne` in derive(PartialEq)](https://github.com/rust-lang/rust/pull/98655/)
+- [Windows RNG: Use `BCRYPT_RNG_ALG_HANDLE` by default](https://github.com/rust-lang/rust/pull/101325/)
+- [Forbid mixing `System` with direct system allocator calls](https://github.com/rust-lang/rust/pull/101394/)
+- [Document no support for writing to non-blocking stdio/stderr](https://github.com/rust-lang/rust/pull/101416/)
+- [`std::layout::Layout` size must not overflow `isize::MAX` when rounded up to `align`](https://github.com/rust-lang/rust/pull/95295)
+ This also changes the safety conditions on `Layout::from_size_align_unchecked`.
+
+Stabilized APIs
+---------------
+
+- [`std::backtrace::Backtrace`](https://doc.rust-lang.org/stable/std/backtrace/struct.Backtrace.html)
+- [`Bound::as_ref`](https://doc.rust-lang.org/stable/std/ops/enum.Bound.html#method.as_ref)
+- [`std::io::read_to_string`](https://doc.rust-lang.org/stable/std/io/fn.read_to_string.html)
+- [`<*const T>::cast_mut`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.cast_mut)
+- [`<*mut T>::cast_const`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.cast_const)
+
+These APIs are now stable in const contexts:
+
+- [`<*const T>::offset_from`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset_from)
+- [`<*mut T>::offset_from`](https://doc.rust-lang.org/stable/std/primitive.pointer.html#method.offset_from)
+
+Cargo
+-----
+
+- [Apply GitHub fast path even for partial hashes](https://github.com/rust-lang/cargo/pull/10807/)
+- [Do not add home bin path to PATH if it's already there](https://github.com/rust-lang/cargo/pull/11023/)
+- [Take priority into account within the pending queue](https://github.com/rust-lang/cargo/pull/11032/).
+ This slightly optimizes job scheduling by Cargo, with typically small improvements on larger crate graph builds.
+
+Compatibility Notes
+-------------------
+
+- [`std::layout::Layout` size must not overflow `isize::MAX` when rounded up to `align`](https://github.com/rust-lang/rust/pull/95295).
+ This also changes the safety conditions on `Layout::from_size_align_unchecked`.
+- [`PollFn` now only implements `Unpin` if the closure is `Unpin`](https://github.com/rust-lang/rust/pull/102737).
+ This is a possible breaking change if users were relying on the blanket unpin implementation.
+ See discussion on the PR for details of why this change was made.
+- [Drop ExactSizeIterator impl from std::char::EscapeAscii](https://github.com/rust-lang/rust/pull/99880)
+ This is a backwards-incompatible change to the standard library's surface
+ area, but is unlikely to affect real world usage.
+- [Do not consider a single repeated lifetime eligible for elision in the return type](https://github.com/rust-lang/rust/pull/103450)
+ This behavior was unintentionally changed in 1.64.0, and this release reverts that change by making this an error again.
+- [Reenable disabled early syntax gates as future-incompatibility lints](https://github.com/rust-lang/rust/pull/99935/)
+- [Update the minimum external LLVM to 13](https://github.com/rust-lang/rust/pull/100460/)
+- [Don't duplicate file descriptors into stdio fds](https://github.com/rust-lang/rust/pull/101426/)
+- [Sunset RLS](https://github.com/rust-lang/rust/pull/100863/)
+- [Deny usage of `#![cfg_attr(..., crate_type = ...)]` to set the crate type](https://github.com/rust-lang/rust/pull/99784/)
+ This strengthens the forward compatibility lint deprecated_cfg_attr_crate_type_name to deny.
+- [`llvm-has-rust-patches` allows setting the build system to treat the LLVM as having Rust-specific patches](https://github.com/rust-lang/rust/pull/101072)
+ This option may need to be set for distributions that are building Rust with a patched LLVM via `llvm-config`, not the built-in LLVM.
+- Combining three or more languages (e.g. Objective C, C++ and Rust) into one binary may hit linker limitations when using `lld`. For more information, see [issue 102754][102754].
+
+[102754]: https://github.com/rust-lang/rust/issues/102754
+
+Internal Changes
+----------------
+
+These changes do not affect any public interfaces of Rust, but they represent
+significant improvements to the performance or internals of rustc and related
+tools.
+
+- [Add `x.sh` and `x.ps1` shell scripts](https://github.com/rust-lang/rust/pull/99992/)
+- [compiletest: use target cfg instead of hard-coded tables](https://github.com/rust-lang/rust/pull/100260/)
+- [Use object instead of LLVM for reading bitcode from rlibs](https://github.com/rust-lang/rust/pull/98100/)
+- [Enable MIR inlining for optimized compilations](https://github.com/rust-lang/rust/pull/91743)
+ This provides a 3-10% improvement in compiletimes for real world crates. See [perf results](https://perf.rust-lang.org/compare.html?start=aedf78e56b2279cc869962feac5153b6ba7001ed&end=0075bb4fad68e64b6d1be06bf2db366c30bc75e1&stat=instructions:u).
+
Version 1.64.0 (2022-09-22)
===========================
rustc_serialize = { path = "../rustc_serialize" }
rustc_span = { path = "../rustc_span" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
-thin-vec = "0.2.8"
+thin-vec = "0.2.9"
tracing = "0.1"
}
impl Expr {
- /// Returns `true` if this expression would be valid somewhere that expects a value;
- /// for example, an `if` condition.
- pub fn returns(&self) -> bool {
- if let ExprKind::Block(ref block, _) = self.kind {
- match block.stmts.last().map(|last_stmt| &last_stmt.kind) {
- // Implicit return
- Some(StmtKind::Expr(_)) => true,
- // Last statement is an explicit return?
- Some(StmtKind::Semi(expr)) => matches!(expr.kind, ExprKind::Ret(_)),
- // This is a block that doesn't end in either an implicit or explicit return.
- _ => false,
- }
- } else {
- // This is not a block, it is a value.
- true
- }
- }
-
/// Is this expr either `N`, or `{ N }`.
///
/// If this is not the case, name resolution does not resolve `N` when using
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
-thin-vec = "0.2.8"
+thin-vec = "0.2.9"
tracing = "0.1"
pub struct SubTupleBinding<'a> {
#[primary_span]
#[label]
- #[suggestion_verbose(
+ #[suggestion(
ast_lowering_sub_tuple_binding_suggestion,
+ style = "verbose",
code = "..",
applicability = "maybe-incorrect"
)]
fn visit_nested_item(&mut self, item: ItemId) {
debug!("visit_nested_item: {:?}", item);
- self.insert_nested(item.def_id.def_id);
+ self.insert_nested(item.owner_id.def_id);
}
fn visit_nested_trait_item(&mut self, item_id: TraitItemId) {
- self.insert_nested(item_id.def_id.def_id);
+ self.insert_nested(item_id.owner_id.def_id);
}
fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
- self.insert_nested(item_id.def_id.def_id);
+ self.insert_nested(item_id.owner_id.def_id);
}
fn visit_nested_foreign_item(&mut self, foreign_id: ForeignItemId) {
- self.insert_nested(foreign_id.def_id.def_id);
+ self.insert_nested(foreign_id.owner_id.def_id);
}
fn visit_nested_body(&mut self, id: BodyId) {
#[instrument(level = "debug", skip(self))]
fn visit_item(&mut self, i: &'hir Item<'hir>) {
- debug_assert_eq!(i.def_id, self.owner);
+ debug_assert_eq!(i.owner_id, self.owner);
self.with_parent(i.hir_id(), |this| {
if let ItemKind::Struct(ref struct_def, _) = i.kind {
// If this is a tuple or unit-like struct, register the constructor.
#[instrument(level = "debug", skip(self))]
fn visit_foreign_item(&mut self, fi: &'hir ForeignItem<'hir>) {
- debug_assert_eq!(fi.def_id, self.owner);
+ debug_assert_eq!(fi.owner_id, self.owner);
self.with_parent(fi.hir_id(), |this| {
intravisit::walk_foreign_item(this, fi);
});
#[instrument(level = "debug", skip(self))]
fn visit_trait_item(&mut self, ti: &'hir TraitItem<'hir>) {
- debug_assert_eq!(ti.def_id, self.owner);
+ debug_assert_eq!(ti.owner_id, self.owner);
self.with_parent(ti.hir_id(), |this| {
intravisit::walk_trait_item(this, ti);
});
#[instrument(level = "debug", skip(self))]
fn visit_impl_item(&mut self, ii: &'hir ImplItem<'hir>) {
- debug_assert_eq!(ii.def_id, self.owner);
+ debug_assert_eq!(ii.owner_id, self.owner);
self.with_parent(ii.hir_id(), |this| {
intravisit::walk_impl_item(this, ii);
});
pub(super) fn lower_item_ref(&mut self, i: &Item) -> SmallVec<[hir::ItemId; 1]> {
let mut node_ids =
- smallvec![hir::ItemId { def_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }];
+ smallvec![hir::ItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } }];
if let ItemKind::Use(ref use_tree) = &i.kind {
self.lower_item_id_use_tree(use_tree, i.id, &mut node_ids);
}
UseTreeKind::Nested(ref nested_vec) => {
for &(ref nested, id) in nested_vec {
vec.push(hir::ItemId {
- def_id: hir::OwnerId { def_id: self.local_def_id(id) },
+ owner_id: hir::OwnerId { def_id: self.local_def_id(id) },
});
self.lower_item_id_use_tree(nested, id, vec);
}
iter::zip(self.expect_full_res_from_use(base_id).skip(1), &[id1, id2])
{
vec.push(hir::ItemId {
- def_id: hir::OwnerId { def_id: self.local_def_id(id) },
+ owner_id: hir::OwnerId { def_id: self.local_def_id(id) },
});
}
}
let attrs = self.lower_attrs(hir_id, &i.attrs);
let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, vis_span, &i.kind);
let item = hir::Item {
- def_id: hir_id.expect_owner(),
+ owner_id: hir_id.expect_owner(),
ident: self.lower_ident(ident),
kind,
vis_span,
}
let item = hir::Item {
- def_id: hir::OwnerId { def_id: new_id },
+ owner_id: hir::OwnerId { def_id: new_id },
ident: this.lower_ident(ident),
kind,
vis_span,
}
let item = hir::Item {
- def_id: hir::OwnerId { def_id: new_hir_id },
+ owner_id: hir::OwnerId { def_id: new_hir_id },
ident: this.lower_ident(ident),
kind,
vis_span,
fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> {
let hir_id = self.lower_node_id(i.id);
- let def_id = hir_id.expect_owner();
+ let owner_id = hir_id.expect_owner();
self.lower_attrs(hir_id, &i.attrs);
let item = hir::ForeignItem {
- def_id,
+ owner_id,
ident: self.lower_ident(i.ident),
kind: match i.kind {
ForeignItemKind::Fn(box Fn { ref sig, ref generics, .. }) => {
fn lower_foreign_item_ref(&mut self, i: &ForeignItem) -> hir::ForeignItemRef {
hir::ForeignItemRef {
- id: hir::ForeignItemId { def_id: hir::OwnerId { def_id: self.local_def_id(i.id) } },
+ id: hir::ForeignItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } },
ident: self.lower_ident(i.ident),
span: self.lower_span(i.span),
}
self.lower_attrs(hir_id, &i.attrs);
let item = hir::TraitItem {
- def_id: trait_item_def_id,
+ owner_id: trait_item_def_id,
ident: self.lower_ident(i.ident),
generics,
kind,
}
AssocItemKind::MacCall(..) => unimplemented!(),
};
- let id = hir::TraitItemId { def_id: hir::OwnerId { def_id: self.local_def_id(i.id) } };
+ let id = hir::TraitItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } };
hir::TraitItemRef {
id,
ident: self.lower_ident(i.ident),
let hir_id = self.lower_node_id(i.id);
self.lower_attrs(hir_id, &i.attrs);
let item = hir::ImplItem {
- def_id: hir_id.expect_owner(),
+ owner_id: hir_id.expect_owner(),
ident: self.lower_ident(i.ident),
generics,
kind,
fn lower_impl_item_ref(&mut self, i: &AssocItem) -> hir::ImplItemRef {
hir::ImplItemRef {
- id: hir::ImplItemId { def_id: hir::OwnerId { def_id: self.local_def_id(i.id) } },
+ id: hir::ImplItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } },
ident: self.lower_ident(i.ident),
span: self.lower_span(i.span),
kind: match &i.kind {
// `impl Trait` now just becomes `Foo<'a, 'b, ..>`.
hir::TyKind::OpaqueDef(
- hir::ItemId { def_id: hir::OwnerId { def_id: opaque_ty_def_id } },
+ hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
lifetimes,
in_trait,
)
// Generate an `type Foo = impl Trait;` declaration.
trace!("registering opaque type with id {:#?}", opaque_ty_id);
let opaque_ty_item = hir::Item {
- def_id: hir::OwnerId { def_id: opaque_ty_id },
+ owner_id: hir::OwnerId { def_id: opaque_ty_id },
ident: Ident::empty(),
kind: opaque_ty_item_kind,
vis_span: self.lower_span(span.shrink_to_lo()),
// async fn, so the *type parameters* are inherited. It's
// only the lifetime parameters that we must supply.
let opaque_ty_ref = hir::TyKind::OpaqueDef(
- hir::ItemId { def_id: hir::OwnerId { def_id: opaque_ty_def_id } },
+ hir::ItemId { owner_id: hir::OwnerId { def_id: opaque_ty_def_id } },
generic_args,
in_trait,
);
self.lower_angle_bracketed_parameter_data(data, param_mode, itctx)
}
GenericArgs::Parenthesized(ref data) => match parenthesized_generic_args {
- ParenthesizedGenericArgs::Ok => self.lower_parenthesized_parameter_data(data),
+ ParenthesizedGenericArgs::Ok => {
+ self.lower_parenthesized_parameter_data(data, itctx)
+ }
ParenthesizedGenericArgs::Err => {
// Suggest replacing parentheses with angle brackets `Trait(params...)` to `Trait<params...>`
let sub = if !data.inputs.is_empty() {
fn lower_parenthesized_parameter_data(
&mut self,
data: &ParenthesizedArgs,
+ itctx: &ImplTraitContext,
) -> (GenericArgsCtor<'hir>, bool) {
// Switch to `PassThrough` mode for anonymous lifetimes; this
// means that we permit things like `&Ref<T>`, where `Ref` has
self.lower_ty_direct(ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitParam))
}));
let output_ty = match output {
+ // Only allow `impl Trait` in return position. i.e.:
+ // ```rust
+ // fn f(_: impl Fn() -> impl Debug) -> impl Fn() -> impl Debug
+ // // disallowed --^^^^^^^^^^ allowed --^^^^^^^^^^
+ // ```
+ FnRetTy::Ty(ty)
+ if matches!(itctx, ImplTraitContext::ReturnPositionOpaqueTy { .. })
+ && self.tcx.features().impl_trait_in_fn_trait_return =>
+ {
+ self.lower_ty(&ty, itctx)
+ }
FnRetTy::Ty(ty) => {
self.lower_ty(&ty, &ImplTraitContext::Disallowed(ImplTraitPosition::FnTraitReturn))
}
span: DUMMY_SP,
category: ConstraintCategory::Internal,
variance_info: VarianceDiagInfo::default(),
+ from_closure: false,
})
} else {
None
pub span: Span,
/// What caused this constraint?
- pub category: ConstraintCategory,
+ pub category: ConstraintCategory<'tcx>,
/// Variance diagnostic information
pub variance_info: VarianceDiagInfo<'tcx>,
+
+ /// If this constraint is promoted from closure requirements.
+ pub from_closure: bool,
}
impl<'tcx> fmt::Debug for OutlivesConstraint<'tcx> {
use rustc_infer::infer::region_constraints::RegionConstraintData;
use rustc_infer::infer::RegionVariableOrigin;
use rustc_infer::infer::{InferCtxt, RegionResolutionError, SubregionOrigin, TyCtxtInferExt as _};
-use rustc_infer::traits::{Normalized, ObligationCause, TraitEngine, TraitEngineExt};
+use rustc_infer::traits::ObligationCause;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::RegionVid;
use rustc_middle::ty::UniverseIndex;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc_span::Span;
use rustc_trait_selection::traits::query::type_op;
-use rustc_trait_selection::traits::{SelectionContext, TraitEngineExt as _};
+use rustc_trait_selection::traits::ObligationCtxt;
use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause};
use std::fmt;
error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>;
+ #[instrument(level = "debug", skip(self, mbcx))]
fn report_error(
&self,
mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
) {
let tcx = mbcx.infcx.tcx;
let base_universe = self.base_universe();
+ debug!(?base_universe);
let Some(adjusted_universe) =
placeholder.universe.as_u32().checked_sub(base_universe.as_u32())
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
let (ref infcx, key, _) =
mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
- let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
- type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause);
- try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
+ let ocx = ObligationCtxt::new(infcx);
+ type_op_prove_predicate_with_cause(&ocx, key, cause);
+ try_extract_error_from_fulfill_cx(&ocx, placeholder_region, error_region)
}
}
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
let (ref infcx, key, _) =
mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
- let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
-
- let mut selcx = SelectionContext::new(infcx);
+ let ocx = ObligationCtxt::new(infcx);
// FIXME(lqd): Unify and de-duplicate the following with the actual
// `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
// to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check
// after #85499 lands to see if its fixes have erased this difference.
let (param_env, value) = key.into_parts();
- let Normalized { value: _, obligations } =
- rustc_trait_selection::traits::normalize(&mut selcx, param_env, cause, value.value);
- fulfill_cx.register_predicate_obligations(infcx, obligations);
+ let _ = ocx.normalize(cause, param_env, value.value);
- try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
+ try_extract_error_from_fulfill_cx(&ocx, placeholder_region, error_region)
}
}
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
let (ref infcx, key, _) =
mbcx.infcx.tcx.infer_ctxt().build_with_canonical(cause.span, &self.canonical_query);
- let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
- type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span)).ok()?;
- try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
+ let ocx = ObligationCtxt::new(infcx);
+ type_op_ascribe_user_type_with_span(&ocx, key, Some(cause.span)).ok()?;
+ try_extract_error_from_fulfill_cx(&ocx, placeholder_region, error_region)
}
}
}
}
-#[instrument(skip(fulfill_cx, infcx), level = "debug")]
+#[instrument(skip(ocx), level = "debug")]
fn try_extract_error_from_fulfill_cx<'tcx>(
- mut fulfill_cx: Box<dyn TraitEngine<'tcx> + 'tcx>,
- infcx: &InferCtxt<'tcx>,
+ ocx: &ObligationCtxt<'_, 'tcx>,
placeholder_region: ty::Region<'tcx>,
error_region: Option<ty::Region<'tcx>>,
) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
// We generally shouldn't have errors here because the query was
// already run, but there's no point using `delay_span_bug`
// when we're going to emit an error here anyway.
- let _errors = fulfill_cx.select_all_or_error(infcx);
- let region_constraints = infcx.with_region_constraints(|r| r.clone());
+ let _errors = ocx.select_all_or_error();
+ let region_constraints = ocx.infcx.with_region_constraints(|r| r.clone());
try_extract_error_from_region_constraints(
- infcx,
+ ocx.infcx,
placeholder_region,
error_region,
®ion_constraints,
- |vid| infcx.region_var_origin(vid),
- |vid| infcx.universe_of_region(infcx.tcx.mk_region(ty::ReVar(vid))),
+ |vid| ocx.infcx.region_var_origin(vid),
+ |vid| ocx.infcx.universe_of_region(ocx.infcx.tcx.mk_region(ty::ReVar(vid))),
)
}
+#[instrument(level = "debug", skip(infcx, region_var_origin, universe_of_region))]
fn try_extract_error_from_region_constraints<'tcx>(
infcx: &InferCtxt<'tcx>,
placeholder_region: ty::Region<'tcx>,
use rustc_span::symbol::sym;
use rustc_span::{BytePos, Span, Symbol};
use rustc_trait_selection::infer::InferCtxtExt;
-use rustc_trait_selection::traits::TraitEngineExt as _;
use crate::borrow_set::TwoPhaseActivation;
use crate::borrowck_errors;
else { return; };
// Try to find predicates on *generic params* that would allow copying `ty`
let infcx = tcx.infer_ctxt().build();
- let mut fulfill_cx = <dyn rustc_infer::traits::TraitEngine<'_>>::new(infcx.tcx);
-
let copy_did = infcx.tcx.lang_items().copy_trait().unwrap();
let cause = ObligationCause::new(
span,
self.mir_hir_id(),
rustc_infer::traits::ObligationCauseCode::MiscObligation,
);
- fulfill_cx.register_bound(
+ let errors = rustc_trait_selection::traits::fully_solve_bound(
&infcx,
+ cause,
self.param_env,
// Erase any region vids from the type, which may not be resolved
infcx.tcx.erase_regions(ty),
copy_did,
- cause,
);
- // Select all, including ambiguous predicates
- let errors = fulfill_cx.select_all_or_error(&infcx);
// Only emit suggestion if all required predicates are on generic
let predicates: Result<Vec<_>, _> = errors
borrow_span,
&self.describe_any_place(borrow.borrowed_place.as_ref()),
);
-
- borrow_spans.var_span_label(
+ borrow_spans.var_subdiag(
&mut err,
- {
+ |var_span| {
+ use crate::session_diagnostics::CaptureVarCause::*;
let place = &borrow.borrowed_place;
let desc_place = self.describe_any_place(place.as_ref());
- format!("borrow occurs due to use of {}{}", desc_place, borrow_spans.describe())
+ match borrow_spans {
+ UseSpans::ClosureUse { generator_kind, .. } => match generator_kind {
+ Some(_) => BorrowUsePlaceGenerator { place: desc_place, var_span },
+ None => BorrowUsePlaceClosure { place: desc_place, var_span },
+ },
+ _ => BorrowUsePlace { place: desc_place, var_span },
+ }
},
"mutable",
);
err: &mut Diagnostic,
location: Location,
issued_borrow: &BorrowData<'tcx>,
- explanation: BorrowExplanation,
+ explanation: BorrowExplanation<'tcx>,
) {
let used_in_call = matches!(
explanation,
borrow: &BorrowData<'tcx>,
drop_span: Span,
borrow_spans: UseSpans<'tcx>,
- explanation: BorrowExplanation,
+ explanation: BorrowExplanation<'tcx>,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
debug!(
"report_local_value_does_not_live_long_enough(\
drop_span: Span,
borrow_spans: UseSpans<'tcx>,
proper_span: Span,
- explanation: BorrowExplanation,
+ explanation: BorrowExplanation<'tcx>,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
if let BorrowExplanation::MustBeValidFor { category, span, from_closure: false, .. } =
explanation
borrow: &BorrowData<'tcx>,
borrow_span: Span,
return_span: Span,
- category: ConstraintCategory,
+ category: ConstraintCategory<'tcx>,
opt_place_desc: Option<&String>,
) -> Option<DiagnosticBuilder<'cx, ErrorGuaranteed>> {
let return_kind = match category {
use_span: UseSpans<'tcx>,
var_span: Span,
fr_name: &RegionName,
- category: ConstraintCategory,
+ category: ConstraintCategory<'tcx>,
constraint_span: Span,
captured_var: &str,
) -> DiagnosticBuilder<'cx, ErrorGuaranteed> {
use super::{find_use, RegionName, UseSpans};
#[derive(Debug)]
-pub(crate) enum BorrowExplanation {
+pub(crate) enum BorrowExplanation<'tcx> {
UsedLater(LaterUseKind, Span, Option<Span>),
UsedLaterInLoop(LaterUseKind, Span, Option<Span>),
UsedLaterWhenDropped {
should_note_order: bool,
},
MustBeValidFor {
- category: ConstraintCategory,
+ category: ConstraintCategory<'tcx>,
from_closure: bool,
span: Span,
region_name: RegionName,
Other,
}
-impl<'tcx> BorrowExplanation {
+impl<'tcx> BorrowExplanation<'tcx> {
pub(crate) fn is_explained(&self) -> bool {
!matches!(self, BorrowExplanation::Unexplained)
}
fn add_lifetime_bound_suggestion_to_diagnostic(
&self,
err: &mut Diagnostic,
- category: &ConstraintCategory,
+ category: &ConstraintCategory<'tcx>,
span: Span,
region_name: &RegionName,
) {
&self,
borrow_region: RegionVid,
outlived_region: RegionVid,
- ) -> (ConstraintCategory, bool, Span, Option<RegionName>, Vec<ExtraConstraintInfo>) {
+ ) -> (ConstraintCategory<'tcx>, bool, Span, Option<RegionName>, Vec<ExtraConstraintInfo>) {
let (blame_constraint, extra_info) = self.regioncx.best_blame_constraint(
borrow_region,
NllRegionVariableOrigin::FreeRegion,
location: Location,
borrow: &BorrowData<'tcx>,
kind_place: Option<(WriteKind, Place<'tcx>)>,
- ) -> BorrowExplanation {
+ ) -> BorrowExplanation<'tcx> {
let regioncx = &self.regioncx;
let body: &Body<'_> = &self.body;
let tcx = self.infcx.tcx;
}
}
+ /// Add a subdiagnostic to the use of the captured variable, if it exists.
+ pub(super) fn var_subdiag(
+ self,
+ err: &mut Diagnostic,
+ f: impl Fn(Span) -> crate::session_diagnostics::CaptureVarCause,
+ kind_desc: impl Into<String>,
+ ) {
+ if let UseSpans::ClosureUse { capture_kind_span, path_span, .. } = self {
+ if capture_kind_span == path_span {
+ err.subdiagnostic(f(capture_kind_span));
+ } else {
+ err.subdiagnostic(crate::session_diagnostics::CaptureVarKind {
+ kind_desc: kind_desc.into(),
+ kind_span: capture_kind_span,
+ });
+ err.subdiagnostic(f(path_span));
+ }
+ }
+ }
+
/// Returns `false` if this place is not used in a closure.
pub(super) fn for_closure(&self) -> bool {
match *self {
pub(crate) fn intermediate_suggestion(
&mut self,
mbcx: &MirBorrowckCtxt<'_, '_>,
- errci: &ErrorConstraintInfo,
+ errci: &ErrorConstraintInfo<'_>,
diag: &mut Diagnostic,
) {
// Emit an intermediate note.
#![deny(rustc::diagnostic_outside_of_impl)]
//! Error reporting machinery for lifetime errors.
-use either::Either;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::Visitor;
NllRegionVariableOrigin, RelateParamBound,
};
use rustc_middle::hir::place::PlaceBase;
-use rustc_middle::mir::{ConstraintCategory, ReturnConstraint, TerminatorKind};
+use rustc_middle::mir::{ConstraintCategory, ReturnConstraint};
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::Region;
use rustc_middle::ty::TypeVisitor;
MirBorrowckCtxt,
};
-impl ConstraintDescription for ConstraintCategory {
+impl<'tcx> ConstraintDescription for ConstraintCategory<'tcx> {
fn description(&self) -> &'static str {
// Must end with a space. Allows for empty names to be provided.
match self {
/// Information about the various region constraints involved in a borrow checker error.
#[derive(Clone, Debug)]
-pub struct ErrorConstraintInfo {
+pub struct ErrorConstraintInfo<'tcx> {
// fr: outlived_fr
pub(super) fr: RegionVid,
pub(super) fr_is_local: bool,
pub(super) outlived_fr_is_local: bool,
// Category and span for best blame constraint
- pub(super) category: ConstraintCategory,
+ pub(super) category: ConstraintCategory<'tcx>,
pub(super) span: Span,
}
// Try to convert the lower-bound region into something named we can print for the user.
let lower_bound_region = self.to_error_region(type_test.lower_bound);
- let type_test_span = type_test.locations.span(&self.body);
+ let type_test_span = type_test.span;
if let Some(lower_bound_region) = lower_bound_region {
let generic_ty = type_test.generic_kind.to_ty(self.infcx.tcx);
fn get_impl_ident_and_self_ty_from_trait(
&self,
def_id: DefId,
- trait_objects: &FxHashSet<DefId>,
+ trait_objects: &FxIndexSet<DefId>,
) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
let tcx = self.infcx.tcx;
match tcx.hir().get_if_local(def_id) {
/// ```
fn report_fnmut_error(
&self,
- errci: &ErrorConstraintInfo,
+ errci: &ErrorConstraintInfo<'tcx>,
kind: ReturnConstraint,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let ErrorConstraintInfo { outlived_fr, span, .. } = errci;
#[instrument(level = "debug", skip(self))]
fn report_escaping_data_error(
&self,
- errci: &ErrorConstraintInfo,
+ errci: &ErrorConstraintInfo<'tcx>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let ErrorConstraintInfo { span, category, .. } = errci;
/// ```
fn report_general_error(
&self,
- errci: &ErrorConstraintInfo,
+ errci: &ErrorConstraintInfo<'tcx>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
let ErrorConstraintInfo {
fr,
diag: &mut Diagnostic,
f: Region<'tcx>,
o: Region<'tcx>,
- category: &ConstraintCategory,
+ category: &ConstraintCategory<'tcx>,
) {
if !o.is_static() {
return;
let tcx = self.infcx.tcx;
- let instance =
- if let ConstraintCategory::CallArgument(location) = category
- && let Either::Right(term) = self.body.stmt_at(*location)
- && let TerminatorKind::Call { func, .. } = &term.kind
- {
- let func_ty = func.ty(self.body, tcx);
+ let instance = if let ConstraintCategory::CallArgument(Some(func_ty)) = category {
let (fn_did, substs) = match func_ty.kind() {
ty::FnDef(fn_did, substs) => (fn_did, substs),
_ => return,
};
debug!(?param);
- let mut visitor = TraitObjectVisitor(FxHashSet::default());
+ let mut visitor = TraitObjectVisitor(FxIndexSet::default());
visitor.visit_ty(param.param_ty);
let Some((ident, self_ty)) =
fn suggest_constrain_dyn_trait_in_impl(
&self,
err: &mut Diagnostic,
- found_dids: &FxHashSet<DefId>,
+ found_dids: &FxIndexSet<DefId>,
ident: Ident,
self_ty: &hir::Ty<'_>,
) -> bool {
})
}
- ty::BoundRegionKind::BrAnon(_) => None,
+ ty::BoundRegionKind::BrAnon(..) => None,
},
ty::ReLateBound(..) | ty::ReVar(..) | ty::RePlaceholder(..) | ty::ReErased => None,
mut liveness_constraints,
outlives_constraints,
member_constraints,
- closure_bounds_mapping,
universe_causes,
type_tests,
} = constraints;
universal_region_relations,
outlives_constraints,
member_constraints,
- closure_bounds_mapping,
universe_causes,
type_tests,
liveness_constraints,
let mut constraints: Vec<_> = self.constraints.outlives().iter().collect();
constraints.sort_by_key(|c| (c.sup, c.sub));
for constraint in &constraints {
- let OutlivesConstraint { sup, sub, locations, category, span, variance_info: _ } =
- constraint;
+ let OutlivesConstraint { sup, sub, locations, category, span, .. } = constraint;
let (name, arg) = match locations {
Locations::All(span) => {
("All", tcx.sess.source_map().span_to_embeddable_string(*span))
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::graph::scc::Sccs;
use rustc_errors::Diagnostic;
-use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
+use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_hir::CRATE_HIR_ID;
use rustc_index::vec::IndexVec;
-use rustc_infer::infer::canonical::QueryOutlivesConstraint;
use rustc_infer::infer::outlives::test_type_match;
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
};
use rustc_middle::traits::ObligationCause;
use rustc_middle::traits::ObligationCauseCode;
-use rustc_middle::ty::{
- self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitable,
-};
+use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitable};
use rustc_span::Span;
use crate::{
/// `member_region_scc`.
member_constraints_applied: Vec<AppliedMemberConstraint>,
- /// Map closure bounds to a `Span` that should be used for error reporting.
- closure_bounds_mapping:
- FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
-
/// Map universe indexes to information on why we created it.
universe_causes: FxHashMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
/// The region `'x` that the type must outlive.
pub lower_bound: RegionVid,
- /// Where did this constraint arise and why?
- pub locations: Locations,
+ /// The span to blame.
+ pub span: Span,
/// A test which, if met by the region `'x`, proves that this type
/// constraint is satisfied.
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,
outlives_constraints: OutlivesConstraintSet<'tcx>,
member_constraints_in: MemberConstraintSet<'tcx, RegionVid>,
- closure_bounds_mapping: FxHashMap<
- Location,
- FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>,
- >,
universe_causes: FxHashMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
type_tests: Vec<TypeTest<'tcx>>,
liveness_constraints: LivenessValues<RegionVid>,
rev_scc_graph: None,
member_constraints,
member_constraints_applied: Vec::new(),
- closure_bounds_mapping,
universe_causes,
scc_universes,
scc_representatives,
if deduplicate_errors.insert((
erased_generic_kind,
type_test.lower_bound,
- type_test.locations,
+ type_test.span,
)) {
debug!(
"check_type_test: reporting error for erased_generic_kind={:?}, \
lower_bound_region={:?}, \
- type_test.locations={:?}",
- erased_generic_kind, type_test.lower_bound, type_test.locations,
+ type_test.span={:?}",
+ erased_generic_kind, type_test.lower_bound, type_test.span,
);
errors_buffer.push(RegionErrorKind::TypeTestError { type_test: type_test.clone() });
) -> bool {
let tcx = infcx.tcx;
- let TypeTest { generic_kind, lower_bound, locations, verify_bound: _ } = type_test;
+ let TypeTest { generic_kind, lower_bound, span: _, verify_bound: _ } = type_test;
let generic_ty = generic_kind.to_ty(tcx);
let Some(subject) = self.try_promote_type_test_subject(infcx, generic_ty) else {
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
subject,
outlived_free_region: static_r,
- blame_span: locations.span(body),
+ blame_span: type_test.span,
category: ConstraintCategory::Boring,
});
let requirement = ClosureOutlivesRequirement {
subject,
outlived_free_region: upper_bound,
- blame_span: locations.span(body),
+ blame_span: type_test.span,
category: ConstraintCategory::Boring,
};
debug!("try_promote_type_test: pushing {:#?}", requirement);
}
}
- pub(crate) fn retrieve_closure_constraint_info(
- &self,
- constraint: OutlivesConstraint<'tcx>,
- ) -> Option<(ConstraintCategory, Span)> {
- match constraint.locations {
- Locations::All(_) => None,
- Locations::Single(loc) => {
- self.closure_bounds_mapping[&loc].get(&(constraint.sup, constraint.sub)).copied()
- }
- }
- }
-
/// Finds a good `ObligationCause` to blame for the fact that `fr1` outlives `fr2`.
pub(crate) fn find_outlives_blame_span(
&self,
fr1: RegionVid,
fr1_origin: NllRegionVariableOrigin,
fr2: RegionVid,
- ) -> (ConstraintCategory, ObligationCause<'tcx>) {
+ ) -> (ConstraintCategory<'tcx>, ObligationCause<'tcx>) {
let BlameConstraint { category, cause, .. } = self
.best_blame_constraint(fr1, fr1_origin, |r| self.provides_universal_region(r, fr1, fr2))
.0;
span: p_c.definition_span,
category: ConstraintCategory::OpaqueType,
variance_info: ty::VarianceDiagInfo::default(),
+ from_closure: false,
};
handle_constraint(constraint);
}
// Classify each of the constraints along the path.
let mut categorized_path: Vec<BlameConstraint<'tcx>> = path
.iter()
- .map(|constraint| {
- let (category, span, from_closure, cause_code) =
- if constraint.category == ConstraintCategory::ClosureBounds {
- if let Some((category, span)) =
- self.retrieve_closure_constraint_info(*constraint)
- {
- (category, span, true, ObligationCauseCode::MiscObligation)
- } else {
- (
- constraint.category,
- constraint.span,
- false,
- ObligationCauseCode::MiscObligation,
- )
- }
- } else {
- (constraint.category, constraint.span, false, cause_code.clone())
- };
- BlameConstraint {
- category,
- from_closure,
- cause: ObligationCause::new(span, CRATE_HIR_ID, cause_code),
- variance_info: constraint.variance_info,
- outlives_constraint: *constraint,
- }
+ .map(|constraint| BlameConstraint {
+ category: constraint.category,
+ from_closure: constraint.from_closure,
+ cause: ObligationCause::new(constraint.span, CRATE_HIR_ID, cause_code.clone()),
+ variance_info: constraint.variance_info,
+ outlives_constraint: *constraint,
})
.collect();
debug!("categorized_path={:#?}", categorized_path);
}
}
-pub trait ClosureRegionRequirementsExt<'tcx> {
- fn apply_requirements(
- &self,
- tcx: TyCtxt<'tcx>,
- closure_def_id: DefId,
- closure_substs: SubstsRef<'tcx>,
- ) -> Vec<QueryOutlivesConstraint<'tcx>>;
-}
-
-impl<'tcx> ClosureRegionRequirementsExt<'tcx> for ClosureRegionRequirements<'tcx> {
- /// Given an instance T of the closure type, this method
- /// instantiates the "extra" requirements that we computed for the
- /// closure into the inference context. This has the effect of
- /// adding new outlives obligations to existing variables.
- ///
- /// As described on `ClosureRegionRequirements`, the extra
- /// requirements are expressed in terms of regionvids that index
- /// into the free regions that appear on the closure type. So, to
- /// do this, we first copy those regions out from the type T into
- /// a vector. Then we can just index into that vector to extract
- /// out the corresponding region from T and apply the
- /// requirements.
- fn apply_requirements(
- &self,
- tcx: TyCtxt<'tcx>,
- closure_def_id: DefId,
- closure_substs: SubstsRef<'tcx>,
- ) -> Vec<QueryOutlivesConstraint<'tcx>> {
- debug!(
- "apply_requirements(closure_def_id={:?}, closure_substs={:?})",
- closure_def_id, closure_substs
- );
-
- // Extract the values of the free regions in `closure_substs`
- // into a vector. These are the regions that we will be
- // relating to one another.
- let closure_mapping = &UniversalRegions::closure_mapping(
- tcx,
- closure_substs,
- self.num_external_vids,
- tcx.typeck_root_def_id(closure_def_id),
- );
- debug!("apply_requirements: closure_mapping={:?}", closure_mapping);
-
- // Create the predicates.
- self.outlives_requirements
- .iter()
- .map(|outlives_requirement| {
- let outlived_region = closure_mapping[outlives_requirement.outlived_free_region];
-
- match outlives_requirement.subject {
- ClosureOutlivesSubject::Region(region) => {
- let region = closure_mapping[region];
- debug!(
- "apply_requirements: region={:?} \
- outlived_region={:?} \
- outlives_requirement={:?}",
- region, outlived_region, outlives_requirement,
- );
- (
- ty::Binder::dummy(ty::OutlivesPredicate(
- region.into(),
- outlived_region,
- )),
- ConstraintCategory::BoringNoLocation,
- )
- }
-
- ClosureOutlivesSubject::Ty(ty) => {
- debug!(
- "apply_requirements: ty={:?} \
- outlived_region={:?} \
- outlives_requirement={:?}",
- ty, outlived_region, outlives_requirement,
- );
- (
- ty::Binder::dummy(ty::OutlivesPredicate(ty.into(), outlived_region)),
- ConstraintCategory::BoringNoLocation,
- )
- }
- }
- })
- .collect()
- }
-}
-
#[derive(Clone, Debug)]
pub struct BlameConstraint<'tcx> {
- pub category: ConstraintCategory,
+ pub category: ConstraintCategory<'tcx>,
pub from_closure: bool,
pub cause: ObligationCause<'tcx>,
pub variance_info: ty::VarianceDiagInfo<'tcx>,
use rustc_hir::OpaqueTyOrigin;
use rustc_infer::infer::TyCtxtInferExt as _;
use rustc_infer::infer::{DefiningAnchor, InferCtxt};
-use rustc_infer::traits::{Obligation, ObligationCause, TraitEngine};
+use rustc_infer::traits::{Obligation, ObligationCause};
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{
};
use rustc_span::Span;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
-use rustc_trait_selection::traits::TraitEngineExt as _;
+use rustc_trait_selection::traits::ObligationCtxt;
use super::RegionInferenceContext;
// type-alias-impl-trait/issue-67844-nested-opaque.rs
let infcx =
self.tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).build();
+ let ocx = ObligationCtxt::new(&infcx);
// Require the hidden type to be well-formed with only the generics of the opaque type.
// Defining use functions may have more bounds than the opaque type, which is ok, as long as the
// hidden type is well formed even without those bounds.
let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(definition_ty.into()))
.to_predicate(infcx.tcx);
- let mut fulfillment_cx = <dyn TraitEngine<'tcx>>::new(infcx.tcx);
let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id.to_def_id());
// Require that the hidden type actually fulfills all the bounds of the opaque type, even without
// the bounds that the function supplies.
- match infcx.register_hidden_type(
- OpaqueTypeKey { def_id, substs: id_substs },
- ObligationCause::misc(instantiated_ty.span, body_id),
+ let opaque_ty = self.tcx.mk_opaque(def_id.to_def_id(), id_substs);
+ if let Err(err) = ocx.eq(
+ &ObligationCause::misc(instantiated_ty.span, body_id),
param_env,
+ opaque_ty,
definition_ty,
- origin,
) {
- Ok(infer_ok) => {
- for obligation in infer_ok.obligations {
- fulfillment_cx.register_predicate_obligation(&infcx, obligation);
- }
- }
- Err(err) => {
- infcx
- .err_ctxt()
- .report_mismatched_types(
- &ObligationCause::misc(instantiated_ty.span, body_id),
- self.tcx.mk_opaque(def_id.to_def_id(), id_substs),
- definition_ty,
- err,
- )
- .emit();
- }
+ infcx
+ .err_ctxt()
+ .report_mismatched_types(
+ &ObligationCause::misc(instantiated_ty.span, body_id),
+ opaque_ty,
+ definition_ty,
+ err,
+ )
+ .emit();
}
- fulfillment_cx.register_predicate_obligation(
- &infcx,
- Obligation::misc(instantiated_ty.span, body_id, param_env, predicate),
- );
+ ocx.register_obligation(Obligation::misc(
+ instantiated_ty.span,
+ body_id,
+ param_env,
+ predicate,
+ ));
// Check that all obligations are satisfied by the implementation's
// version.
- let errors = fulfillment_cx.select_all_or_error(&infcx);
+ let errors = ocx.select_all_or_error();
// This is still required for many(half of the tests in ui/type-alias-impl-trait)
// tests to pass
if errors.is_empty() {
definition_ty
} else {
- infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
- self.tcx.ty_error()
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
+ self.tcx.ty_error_with_guaranteed(reported)
}
}
}
#[derive(LintDiagnostic)]
#[diag(borrowck_var_does_not_need_mut)]
pub(crate) struct VarNeedNotMut {
- #[suggestion_short(applicability = "machine-applicable", code = "")]
+ #[suggestion(style = "short", applicability = "machine-applicable", code = "")]
pub span: Span,
}
#[derive(Diagnostic)]
multi_span: MultiSpan,
},
}
+
+#[derive(Subdiagnostic)]
+#[label(borrowck_capture_kind_label)]
+pub(crate) struct CaptureVarKind {
+ pub kind_desc: String,
+ #[primary_span]
+ pub kind_span: Span,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum CaptureVarCause {
+ #[label(borrowck_var_borrow_by_use_place)]
+ BorrowUsePlace {
+ place: String,
+ #[primary_span]
+ var_span: Span,
+ },
+ #[label(borrowck_var_borrow_by_use_place_in_generator)]
+ BorrowUsePlaceGenerator {
+ place: String,
+ #[primary_span]
+ var_span: Span,
+ },
+ #[label(borrowck_var_borrow_by_use_place_in_closure)]
+ BorrowUsePlaceClosure {
+ place: String,
+ #[primary_span]
+ var_span: Span,
+ },
+}
pub(super) fn fully_perform_op<R: fmt::Debug, Op>(
&mut self,
locations: Locations,
- category: ConstraintCategory,
+ category: ConstraintCategory<'tcx>,
op: Op,
) -> Fallible<R>
where
&mut self,
trait_ref: ty::TraitRef<'tcx>,
locations: Locations,
- category: ConstraintCategory,
+ category: ConstraintCategory<'tcx>,
) {
self.prove_predicate(
ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
&mut self,
predicates: impl IntoIterator<Item = impl ToPredicate<'tcx>>,
locations: Locations,
- category: ConstraintCategory,
+ category: ConstraintCategory<'tcx>,
) {
for predicate in predicates {
let predicate = predicate.to_predicate(self.tcx());
&mut self,
predicate: ty::Predicate<'tcx>,
locations: Locations,
- category: ConstraintCategory,
+ category: ConstraintCategory<'tcx>,
) {
let param_env = self.param_env;
self.fully_perform_op(
&mut self,
value: T,
location: impl NormalizeLocation,
- category: ConstraintCategory,
+ category: ConstraintCategory<'tcx>,
) -> T
where
T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
-use rustc_infer::infer::canonical::QueryOutlivesConstraint;
+use rustc_hir::def_id::DefId;
use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_infer::infer::outlives::env::RegionBoundPairs;
use rustc_infer::infer::outlives::obligations::{TypeOutlives, TypeOutlivesDelegate};
use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound};
use rustc_infer::infer::{self, InferCtxt, SubregionOrigin};
-use rustc_middle::mir::ConstraintCategory;
+use rustc_middle::mir::{ClosureOutlivesSubject, ClosureRegionRequirements, ConstraintCategory};
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::TypeFoldable;
use rustc_middle::ty::{self, TyCtxt};
param_env: ty::ParamEnv<'tcx>,
locations: Locations,
span: Span,
- category: ConstraintCategory,
+ category: ConstraintCategory<'tcx>,
+ from_closure: bool,
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
}
param_env: ty::ParamEnv<'tcx>,
locations: Locations,
span: Span,
- category: ConstraintCategory,
+ category: ConstraintCategory<'tcx>,
constraints: &'a mut MirTypeckRegionConstraints<'tcx>,
) -> Self {
Self {
span,
category,
constraints,
+ from_closure: false,
}
}
}
self.constraints.member_constraints = tmp;
- for query_constraint in outlives {
- self.convert(query_constraint);
+ for (predicate, constraint_category) in outlives {
+ // At the moment, we never generate any "higher-ranked"
+ // region constraints like `for<'a> 'a: 'b`. At some point
+ // when we move to universes, we will, and this assertion
+ // will start to fail.
+ let predicate = predicate.no_bound_vars().unwrap_or_else(|| {
+ bug!("query_constraint {:?} contained bound vars", predicate,);
+ });
+
+ self.convert(predicate, *constraint_category);
+ }
+ }
+
+ /// Given an instance of the closure type, this method instantiates the "extra" requirements
+ /// that we computed for the closure. This has the effect of adding new outlives obligations
+ /// to existing region variables in `closure_substs`.
+ #[instrument(skip(self), level = "debug")]
+ pub fn apply_closure_requirements(
+ &mut self,
+ closure_requirements: &ClosureRegionRequirements<'tcx>,
+ closure_def_id: DefId,
+ closure_substs: ty::SubstsRef<'tcx>,
+ ) {
+ // Extract the values of the free regions in `closure_substs`
+ // into a vector. These are the regions that we will be
+ // relating to one another.
+ let closure_mapping = &UniversalRegions::closure_mapping(
+ self.tcx,
+ closure_substs,
+ closure_requirements.num_external_vids,
+ closure_def_id.expect_local(),
+ );
+ debug!(?closure_mapping);
+
+ // Create the predicates.
+ let backup = (self.category, self.span, self.from_closure);
+ self.from_closure = true;
+ for outlives_requirement in &closure_requirements.outlives_requirements {
+ let outlived_region = closure_mapping[outlives_requirement.outlived_free_region];
+ let subject = match outlives_requirement.subject {
+ ClosureOutlivesSubject::Region(re) => closure_mapping[re].into(),
+ ClosureOutlivesSubject::Ty(ty) => ty.into(),
+ };
+
+ self.category = outlives_requirement.category;
+ self.span = outlives_requirement.blame_span;
+ self.convert(ty::OutlivesPredicate(subject, outlived_region), self.category);
}
+ (self.category, self.span, self.from_closure) = backup;
}
- fn convert(&mut self, query_constraint: &QueryOutlivesConstraint<'tcx>) {
+ fn convert(
+ &mut self,
+ predicate: ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>,
+ constraint_category: ConstraintCategory<'tcx>,
+ ) {
debug!("generate: constraints at: {:#?}", self.locations);
// Extract out various useful fields we'll need below.
tcx, region_bound_pairs, implicit_region_bound, param_env, ..
} = *self;
- // At the moment, we never generate any "higher-ranked"
- // region constraints like `for<'a> 'a: 'b`. At some point
- // when we move to universes, we will, and this assertion
- // will start to fail.
- let ty::OutlivesPredicate(k1, r2) =
- query_constraint.0.no_bound_vars().unwrap_or_else(|| {
- bug!("query_constraint {:?} contained bound vars", query_constraint,);
- });
-
- let constraint_category = query_constraint.1;
-
+ let ty::OutlivesPredicate(k1, r2) = predicate;
match k1.unpack() {
GenericArgKind::Lifetime(r1) => {
let r1_vid = self.to_region_vid(r1);
.type_must_outlive(origin, t1, r2, constraint_category);
}
- GenericArgKind::Const(_) => {
- // Consts cannot outlive one another, so we
- // don't need to handle any relations here.
- }
+ GenericArgKind::Const(_) => unreachable!(),
}
}
verify_bound: VerifyBound<'tcx>,
) -> TypeTest<'tcx> {
let lower_bound = self.to_region_vid(region);
- TypeTest { generic_kind, lower_bound, locations: self.locations, verify_bound }
+ TypeTest { generic_kind, lower_bound, span: self.span, verify_bound }
}
fn to_region_vid(&mut self, r: ty::Region<'tcx>) -> ty::RegionVid {
&mut self,
sup: ty::RegionVid,
sub: ty::RegionVid,
- category: ConstraintCategory,
+ category: ConstraintCategory<'tcx>,
) {
let category = match self.category {
ConstraintCategory::Boring | ConstraintCategory::BoringNoLocation => category,
sub,
sup,
variance_info: ty::VarianceDiagInfo::default(),
+ from_closure: self.from_closure,
});
}
_origin: SubregionOrigin<'tcx>,
a: ty::Region<'tcx>,
b: ty::Region<'tcx>,
- constraint_category: ConstraintCategory,
+ constraint_category: ConstraintCategory<'tcx>,
) {
let b = self.to_region_vid(b);
let a = self.to_region_vid(a);
.and(type_op::normalize::Normalize::new(ty))
.fully_perform(self.infcx)
.unwrap_or_else(|_| {
- self.infcx
+ let reported = self
+ .infcx
.tcx
.sess
.delay_span_bug(span, &format!("failed to normalize {:?}", ty));
TypeOpOutput {
- output: self.infcx.tcx.ty_error(),
+ output: self.infcx.tcx.ty_error_with_guaranteed(reported),
constraints: None,
error_info: None,
}
use rustc_middle::mir::*;
use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::ty::cast::CastTy;
-use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts};
+use rustc_middle::ty::subst::{SubstsRef, UserSubsts};
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{
self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, Dynamic,
region_infer::values::{
LivenessValues, PlaceholderIndex, PlaceholderIndices, RegionValueElements,
},
- region_infer::{ClosureRegionRequirementsExt, TypeTest},
+ region_infer::TypeTest,
type_check::free_region_relations::{CreateResult, UniversalRegionRelations},
universal_regions::{DefiningTy, UniversalRegions},
Upvar,
liveness_constraints: LivenessValues::new(elements.clone()),
outlives_constraints: OutlivesConstraintSet::default(),
member_constraints: MemberConstraintSet::default(),
- closure_bounds_mapping: Default::default(),
type_tests: Vec::default(),
universe_causes: FxHashMap::default(),
};
let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type);
trace!("finalized opaque type {:?} to {:#?}", opaque_type_key, hidden_type.ty.kind());
if hidden_type.has_non_region_infer() {
- infcx.tcx.sess.delay_span_bug(
+ let reported = infcx.tcx.sess.delay_span_bug(
decl.hidden_type.span,
&format!("could not resolve {:#?}", hidden_type.ty.kind()),
);
- hidden_type.ty = infcx.tcx.ty_error();
+ hidden_type.ty = infcx.tcx.ty_error_with_guaranteed(reported);
}
(opaque_type_key, (hidden_type, decl.origin))
// modify their locations.
let all_facts = &mut None;
let mut constraints = Default::default();
- let mut type_tests = Default::default();
- let mut closure_bounds = Default::default();
let mut liveness_constraints =
LivenessValues::new(Rc::new(RegionValueElements::new(&promoted_body)));
// Don't try to add borrow_region facts for the promoted MIR
&mut this.cx.borrowck_context.constraints.outlives_constraints,
&mut constraints,
);
- mem::swap(&mut this.cx.borrowck_context.constraints.type_tests, &mut type_tests);
- mem::swap(
- &mut this.cx.borrowck_context.constraints.closure_bounds_mapping,
- &mut closure_bounds,
- );
mem::swap(
&mut this.cx.borrowck_context.constraints.liveness_constraints,
&mut liveness_constraints,
swap_constraints(self);
let locations = location.to_locations();
-
- // Use location of promoted const in collected constraints
- for type_test in type_tests.iter() {
- let mut type_test = type_test.clone();
- type_test.locations = locations;
- self.cx.borrowck_context.constraints.type_tests.push(type_test)
- }
for constraint in constraints.outlives().iter() {
let mut constraint = constraint.clone();
constraint.locations = locations;
.add_element(region, location);
}
}
-
- if !closure_bounds.is_empty() {
- let combined_bounds_mapping =
- closure_bounds.into_iter().flat_map(|(_, value)| value).collect();
- let existing = self
- .cx
- .borrowck_context
- .constraints
- .closure_bounds_mapping
- .insert(location, combined_bounds_mapping);
- assert!(existing.is_none(), "Multiple promoteds/closures at the same location.");
- }
}
fn sanitize_projection(
pub(crate) member_constraints: MemberConstraintSet<'tcx, RegionVid>,
- pub(crate) closure_bounds_mapping:
- FxHashMap<Location, FxHashMap<(RegionVid, RegionVid), (ConstraintCategory, Span)>>,
-
pub(crate) universe_causes: FxHashMap<ty::UniverseIndex, UniverseInfo<'tcx>>,
pub(crate) type_tests: Vec<TypeTest<'tcx>>,
fn push_region_constraints(
&mut self,
locations: Locations,
- category: ConstraintCategory,
+ category: ConstraintCategory<'tcx>,
data: &QueryRegionConstraints<'tcx>,
) {
debug!("constraints generated: {:#?}", data);
sub: Ty<'tcx>,
sup: Ty<'tcx>,
locations: Locations,
- category: ConstraintCategory,
+ category: ConstraintCategory<'tcx>,
) -> Fallible<()> {
// Use this order of parameters because the sup type is usually the
// "expected" type in diagnostics.
expected: Ty<'tcx>,
found: Ty<'tcx>,
locations: Locations,
- category: ConstraintCategory,
+ category: ConstraintCategory<'tcx>,
) -> Fallible<()> {
self.relate_types(expected, ty::Variance::Invariant, found, locations, category)
}
v: ty::Variance,
user_ty: &UserTypeProjection,
locations: Locations,
- category: ConstraintCategory,
+ category: ConstraintCategory<'tcx>,
) -> Fallible<()> {
let annotated_type = self.user_type_annotations[user_ty.base].inferred_ty;
let mut curr_projected_ty = PlaceTy::from_ty(annotated_type);
span_mirbug!(self, term, "call to {:?} with wrong # of args", sig);
}
+ let func_ty = if let TerminatorKind::Call { func, .. } = &term.kind {
+ Some(func.ty(body, self.infcx.tcx))
+ } else {
+ None
+ };
+ debug!(?func_ty);
+
for (n, (fn_arg, op_arg)) in iter::zip(sig.inputs(), args).enumerate() {
let op_arg_ty = op_arg.ty(body, self.tcx());
let op_arg_ty = self.normalize(op_arg_ty, term_location);
let category = if from_hir_call {
- ConstraintCategory::CallArgument(term_location)
+ ConstraintCategory::CallArgument(self.infcx.tcx.erase_regions(func_ty))
} else {
ConstraintCategory::Boring
};
// `Sized` bound in no way depends on precise regions, so this
// shouldn't affect `is_sized`.
let erased_ty = tcx.erase_regions(ty);
- if !erased_ty.is_sized(tcx.at(span), self.param_env) {
+ if !erased_ty.is_sized(tcx, self.param_env) {
// in current MIR construction, all non-control-flow rvalue
// expressions evaluate through `as_temp` or `into` a return
// slot or local, so to find all unsized rvalues it is enough
span: location.to_locations().span(body),
category,
variance_info: ty::VarianceDiagInfo::default(),
+ from_closure: false,
});
match mutbl {
substs: SubstsRef<'tcx>,
location: Location,
) -> ty::InstantiatedPredicates<'tcx> {
- if let Some(ref closure_region_requirements) = tcx.mir_borrowck(def_id).closure_requirements
- {
- let closure_constraints = QueryRegionConstraints {
- outlives: closure_region_requirements.apply_requirements(
- tcx,
- def_id.to_def_id(),
- substs,
- ),
-
- // Presently, closures never propagate member
- // constraints to their parents -- they are enforced
- // locally. This is largely a non-issue as member
- // constraints only come from `-> impl Trait` and
- // friends which don't appear (thus far...) in
- // closures.
- member_constraints: vec![],
- };
-
- let bounds_mapping = closure_constraints
- .outlives
- .iter()
- .enumerate()
- .filter_map(|(idx, constraint)| {
- let ty::OutlivesPredicate(k1, r2) =
- constraint.0.no_bound_vars().unwrap_or_else(|| {
- bug!("query_constraint {:?} contained bound vars", constraint,);
- });
-
- match k1.unpack() {
- GenericArgKind::Lifetime(r1) => {
- // constraint is r1: r2
- let r1_vid = self.borrowck_context.universal_regions.to_region_vid(r1);
- let r2_vid = self.borrowck_context.universal_regions.to_region_vid(r2);
- let outlives_requirements =
- &closure_region_requirements.outlives_requirements[idx];
- Some((
- (r1_vid, r2_vid),
- (outlives_requirements.category, outlives_requirements.blame_span),
- ))
- }
- GenericArgKind::Type(_) | GenericArgKind::Const(_) => None,
- }
- })
- .collect();
-
- let existing = self
- .borrowck_context
- .constraints
- .closure_bounds_mapping
- .insert(location, bounds_mapping);
- assert!(existing.is_none(), "Multiple closures at the same location.");
-
- self.push_region_constraints(
+ if let Some(ref closure_requirements) = tcx.mir_borrowck(def_id).closure_requirements {
+ constraint_conversion::ConstraintConversion::new(
+ self.infcx,
+ self.borrowck_context.universal_regions,
+ self.region_bound_pairs,
+ self.implicit_region_bound,
+ self.param_env,
location.to_locations(),
- ConstraintCategory::ClosureBounds,
- &closure_constraints,
+ DUMMY_SP, // irrelevant; will be overrided.
+ ConstraintCategory::Boring, // same as above.
+ &mut self.borrowck_context.constraints,
+ )
+ .apply_closure_requirements(
+ &closure_requirements,
+ def_id.to_def_id(),
+ substs,
);
}
use rustc_infer::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
use rustc_infer::infer::NllRegionVariableOrigin;
-use rustc_infer::traits::ObligationCause;
+use rustc_infer::traits::PredicateObligations;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::relate::TypeRelation;
v: ty::Variance,
b: Ty<'tcx>,
locations: Locations,
- category: ConstraintCategory,
+ category: ConstraintCategory<'tcx>,
) -> Fallible<()> {
TypeRelating::new(
self.infcx,
a: ty::SubstsRef<'tcx>,
b: ty::SubstsRef<'tcx>,
locations: Locations,
- category: ConstraintCategory,
+ category: ConstraintCategory<'tcx>,
) -> Fallible<()> {
TypeRelating::new(
self.infcx,
locations: Locations,
/// What category do we assign the resulting `'a: 'b` relationships?
- category: ConstraintCategory,
+ category: ConstraintCategory<'tcx>,
/// Information so that error reporting knows what types we are relating
/// when reporting a bound region error.
fn new(
type_checker: &'me mut TypeChecker<'bccx, 'tcx>,
locations: Locations,
- category: ConstraintCategory,
+ category: ConstraintCategory<'tcx>,
universe_info: UniverseInfo<'tcx>,
) -> Self {
Self { type_checker, locations, category, universe_info }
span: self.locations.span(self.type_checker.body),
category: self.category,
variance_info: info,
+ from_closure: false,
},
);
}
true
}
- fn register_opaque_type(
+ fn register_opaque_type_obligations(
&mut self,
- a: Ty<'tcx>,
- b: Ty<'tcx>,
- a_is_expected: bool,
+ obligations: PredicateObligations<'tcx>,
) -> Result<(), TypeError<'tcx>> {
- let param_env = self.param_env();
- let span = self.span();
- let def_id = self.type_checker.body.source.def_id().expect_local();
- let body_id = self.type_checker.tcx().hir().local_def_id_to_hir_id(def_id);
- let cause = ObligationCause::misc(span, body_id);
self.type_checker
.fully_perform_op(
self.locations,
self.category,
InstantiateOpaqueType {
- obligations: self
- .type_checker
- .infcx
- .handle_opaque_type(a, b, a_is_expected, &cause, param_env)?
- .obligations,
+ obligations,
// These fields are filled in during execution of the operation
base_universe: None,
region_constraints: None,
use rustc_index::vec::{Idx, IndexVec};
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin};
use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt};
+use rustc_middle::ty::{
+ self, DefIdTree, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt,
+};
use rustc_middle::ty::{InternalSubsts, SubstsRef};
use std::iter;
tcx: TyCtxt<'tcx>,
closure_substs: SubstsRef<'tcx>,
expected_num_vars: usize,
- typeck_root_def_id: DefId,
+ closure_def_id: LocalDefId,
) -> IndexVec<RegionVid, ty::Region<'tcx>> {
let mut region_mapping = IndexVec::with_capacity(expected_num_vars);
region_mapping.push(tcx.lifetimes.re_static);
region_mapping.push(fr);
});
- for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
+ for_each_late_bound_region_in_recursive_scope(tcx, tcx.local_parent(closure_def_id), |r| {
region_mapping.push(r);
});
// tests, and the resulting print-outs include def-ids
// and other things that are not stable across tests!
// So we just include the region-vid. Annoying.
- let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
- for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
- err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),));
+ for_each_late_bound_region_in_recursive_scope(tcx, def_id.expect_local(), |r| {
+ err.note(&format!("late-bound region is {:?}", self.to_region_vid(r)));
});
}
DefiningTy::Generator(def_id, substs, _) => {
// FIXME: As above, we'd like to print out the region
// `r` but doing so is not stable across architectures
// and so forth.
- let typeck_root_def_id = tcx.typeck_root_def_id(def_id);
- for_each_late_bound_region_defined_on(tcx, typeck_root_def_id, |r| {
- err.note(&format!("late-bound region is {:?}", self.to_region_vid(r),));
+ for_each_late_bound_region_in_recursive_scope(tcx, def_id.expect_local(), |r| {
+ err.note(&format!("late-bound region is {:?}", self.to_region_vid(r)));
});
}
DefiningTy::FnDef(def_id, substs) => {
first_extern_index
} else {
// If this is a closure, generator, or inline-const, then the late-bound regions from the enclosing
- // function are actually external regions to us. For example, here, 'a is not local
+ // function/closures are actually external regions to us. For example, here, 'a is not local
// to the closure c (although it is local to the fn foo):
// fn foo<'a>() {
// let c = || { let x: &'a u32 = ...; }
// }
- self.infcx
- .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices);
+ for_each_late_bound_region_in_recursive_scope(
+ self.infcx.tcx,
+ self.infcx.tcx.local_parent(self.mir_def.did),
+ |r| {
+ debug!(?r);
+ if !indices.indices.contains_key(&r) {
+ let region_vid = self.infcx.next_nll_region_var(FR);
+ debug!(?region_vid);
+ indices.insert_late_bound_region(r, region_vid.to_region_vid());
+ }
+ },
+ );
+
// Any regions created during the execution of `defining_ty` or during the above
// late-bound region replacement are all considered 'extern' regions
self.infcx.num_region_vars()
bound_inputs_and_output,
&mut indices,
);
- // Converse of above, if this is a function then the late-bound regions declared on its
- // signature are local to the fn.
- if self.mir_def.did.to_def_id() == typeck_root_def_id {
- self.infcx
- .replace_late_bound_regions_with_nll_infer_vars(self.mir_def.did, &mut indices);
- }
+ // Converse of above, if this is a function/closure then the late-bound regions declared on its
+ // signature are local.
+ for_each_late_bound_region_in_item(self.infcx.tcx, self.mir_def.did, |r| {
+ debug!(?r);
+ if !indices.indices.contains_key(&r) {
+ let region_vid = self.infcx.next_nll_region_var(FR);
+ debug!(?region_vid);
+ indices.insert_late_bound_region(r, region_vid.to_region_vid());
+ }
+ });
let (unnormalized_output_ty, mut unnormalized_input_tys) =
inputs_and_output.split_last().unwrap();
where
T: TypeFoldable<'tcx>;
- fn replace_late_bound_regions_with_nll_infer_vars(
+ fn replace_late_bound_regions_with_nll_infer_vars_in_recursive_scope(
+ &self,
+ mir_def_id: LocalDefId,
+ indices: &mut UniversalRegionIndices<'tcx>,
+ );
+
+ fn replace_late_bound_regions_with_nll_infer_vars_in_item(
&self,
mir_def_id: LocalDefId,
indices: &mut UniversalRegionIndices<'tcx>,
/// set of late-bound regions and checks for any that we have not yet seen, adding them to the
/// inputs vector.
#[instrument(skip(self, indices))]
- fn replace_late_bound_regions_with_nll_infer_vars(
+ fn replace_late_bound_regions_with_nll_infer_vars_in_recursive_scope(
+ &self,
+ mir_def_id: LocalDefId,
+ indices: &mut UniversalRegionIndices<'tcx>,
+ ) {
+ for_each_late_bound_region_in_recursive_scope(self.tcx, mir_def_id, |r| {
+ debug!(?r);
+ if !indices.indices.contains_key(&r) {
+ let region_vid = self.next_nll_region_var(FR);
+ debug!(?region_vid);
+ indices.insert_late_bound_region(r, region_vid.to_region_vid());
+ }
+ });
+ }
+
+ #[instrument(skip(self, indices))]
+ fn replace_late_bound_regions_with_nll_infer_vars_in_item(
&self,
mir_def_id: LocalDefId,
indices: &mut UniversalRegionIndices<'tcx>,
) {
- let typeck_root_def_id = self.tcx.typeck_root_def_id(mir_def_id.to_def_id());
- for_each_late_bound_region_defined_on(self.tcx, typeck_root_def_id, |r| {
+ for_each_late_bound_region_in_item(self.tcx, mir_def_id, |r| {
debug!(?r);
if !indices.indices.contains_key(&r) {
let region_vid = self.next_nll_region_var(FR);
}
}
-/// Iterates over the late-bound regions defined on fn_def_id and
-/// invokes `f` with the liberated form of each one.
-fn for_each_late_bound_region_defined_on<'tcx>(
+/// Iterates over the late-bound regions defined on `mir_def_id` and all of its
+/// parents, up to the typeck root, and invokes `f` with the liberated form
+/// of each one.
+fn for_each_late_bound_region_in_recursive_scope<'tcx>(
tcx: TyCtxt<'tcx>,
- fn_def_id: DefId,
+ mut mir_def_id: LocalDefId,
mut f: impl FnMut(ty::Region<'tcx>),
) {
- if let Some(late_bounds) = tcx.is_late_bound_map(fn_def_id.expect_local()) {
- for ®ion_def_id in late_bounds.iter() {
- let name = tcx.item_name(region_def_id.to_def_id());
- let liberated_region = tcx.mk_region(ty::ReFree(ty::FreeRegion {
- scope: fn_def_id,
- bound_region: ty::BoundRegionKind::BrNamed(region_def_id.to_def_id(), name),
- }));
- f(liberated_region);
+ let typeck_root_def_id = tcx.typeck_root_def_id(mir_def_id.to_def_id());
+
+ // Walk up the tree, collecting late-bound regions until we hit the typeck root
+ loop {
+ for_each_late_bound_region_in_item(tcx, mir_def_id, &mut f);
+
+ if mir_def_id.to_def_id() == typeck_root_def_id {
+ break;
+ } else {
+ mir_def_id = tcx.local_parent(mir_def_id);
}
}
}
+
+/// Iterates over the late-bound regions defined on `mir_def_id` and all of its
+/// parents, up to the typeck root, and invokes `f` with the liberated form
+/// of each one.
+fn for_each_late_bound_region_in_item<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ mir_def_id: LocalDefId,
+ mut f: impl FnMut(ty::Region<'tcx>),
+) {
+ if !tcx.def_kind(mir_def_id).is_fn_like() {
+ return;
+ }
+
+ for bound_var in tcx.late_bound_vars(tcx.hir().local_def_id_to_hir_id(mir_def_id)) {
+ let ty::BoundVariableKind::Region(bound_region) = bound_var else { continue; };
+ let liberated_region = tcx
+ .mk_region(ty::ReFree(ty::FreeRegion { scope: mir_def_id.to_def_id(), bound_region }));
+ f(liberated_region);
+ }
+}
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
-thin-vec = "0.2.8"
+thin-vec = "0.2.9"
tracing = "0.1"
--- /dev/null
+use crate::util::check_builtin_macro_attribute;
+
+use rustc_ast::ptr::P;
+use rustc_ast::{self as ast, FnHeader, FnSig, Generics, StmtKind};
+use rustc_ast::{Fn, ItemKind, Stmt, TyKind, Unsafe};
+use rustc_expand::base::{Annotatable, ExtCtxt};
+use rustc_span::symbol::{kw, sym, Ident};
+use rustc_span::Span;
+use thin_vec::thin_vec;
+
+pub fn expand(
+ ecx: &mut ExtCtxt<'_>,
+ _span: Span,
+ meta_item: &ast::MetaItem,
+ item: Annotatable,
+) -> Vec<Annotatable> {
+ check_builtin_macro_attribute(ecx, meta_item, sym::alloc_error_handler);
+
+ let orig_item = item.clone();
+ let not_function = || {
+ ecx.sess
+ .parse_sess
+ .span_diagnostic
+ .span_err(item.span(), "alloc_error_handler must be a function");
+ vec![orig_item.clone()]
+ };
+
+ // Allow using `#[alloc_error_handler]` on an item statement
+ // FIXME - if we get deref patterns, use them to reduce duplication here
+ let (item, is_stmt, sig_span) = match &item {
+ Annotatable::Item(item) => match item.kind {
+ ItemKind::Fn(ref fn_kind) => (item, false, ecx.with_def_site_ctxt(fn_kind.sig.span)),
+ _ => return not_function(),
+ },
+ Annotatable::Stmt(stmt) => match &stmt.kind {
+ StmtKind::Item(item_) => match item_.kind {
+ ItemKind::Fn(ref fn_kind) => {
+ (item_, true, ecx.with_def_site_ctxt(fn_kind.sig.span))
+ }
+ _ => return not_function(),
+ },
+ _ => return not_function(),
+ },
+ _ => return not_function(),
+ };
+
+ // Generate a bunch of new items using the AllocFnFactory
+ let span = ecx.with_def_site_ctxt(item.span);
+
+ // Generate item statements for the allocator methods.
+ let stmts = vec![generate_handler(ecx, item.ident, span, sig_span)];
+
+ // Generate anonymous constant serving as container for the allocator methods.
+ let const_ty = ecx.ty(sig_span, TyKind::Tup(Vec::new()));
+ let const_body = ecx.expr_block(ecx.block(span, stmts));
+ let const_item = ecx.item_const(span, Ident::new(kw::Underscore, span), const_ty, const_body);
+ let const_item = if is_stmt {
+ Annotatable::Stmt(P(ecx.stmt_item(span, const_item)))
+ } else {
+ Annotatable::Item(const_item)
+ };
+
+ // Return the original item and the new methods.
+ vec![orig_item, const_item]
+}
+
+// #[rustc_std_internal_symbol]
+// unsafe fn __rg_oom(size: usize, align: usize) -> ! {
+// handler(core::alloc::Layout::from_size_align_unchecked(size, align))
+// }
+fn generate_handler(cx: &ExtCtxt<'_>, handler: Ident, span: Span, sig_span: Span) -> Stmt {
+ let usize = cx.path_ident(span, Ident::new(sym::usize, span));
+ let ty_usize = cx.ty_path(usize);
+ let size = Ident::from_str_and_span("size", span);
+ let align = Ident::from_str_and_span("align", span);
+
+ let layout_new = cx.std_path(&[sym::alloc, sym::Layout, sym::from_size_align_unchecked]);
+ let layout_new = cx.expr_path(cx.path(span, layout_new));
+ let layout =
+ cx.expr_call(span, layout_new, vec![cx.expr_ident(span, size), cx.expr_ident(span, align)]);
+
+ let call = cx.expr_call_ident(sig_span, handler, vec![layout]);
+
+ let never = ast::FnRetTy::Ty(cx.ty(span, TyKind::Never));
+ let params = vec![cx.param(span, size, ty_usize.clone()), cx.param(span, align, ty_usize)];
+ let decl = cx.fn_decl(params, never);
+ let header = FnHeader { unsafety: Unsafe::Yes(span), ..FnHeader::default() };
+ let sig = FnSig { decl, header, span: span };
+
+ let body = Some(cx.block_expr(call));
+ let kind = ItemKind::Fn(Box::new(Fn {
+ defaultness: ast::Defaultness::Final,
+ sig,
+ generics: Generics::default(),
+ body,
+ }));
+
+ let special = sym::rustc_std_internal_symbol;
+ let special = cx.meta_word(span, special);
+ let attrs = thin_vec![cx.attribute(special)];
+
+ let item = cx.item(span, Ident::from_str_and_span("__rg_oom", span), attrs, kind);
+ cx.stmt_item(sig_span, item)
+}
use rustc_expand::proc_macro::BangProcMacro;
use rustc_span::symbol::sym;
+mod alloc_error_handler;
mod assert;
mod cfg;
mod cfg_accessible;
}
register_attr! {
+ alloc_error_handler: alloc_error_handler::expand,
bench: test::expand_bench,
cfg_accessible: cfg_accessible::Expander,
cfg_eval: cfg_eval::expand,
use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
use rustc_session::config::OomStrategy;
+use rustc_span::symbol::sym;
/// Returns whether an allocator shim was created
pub(crate) fn codegen(
module,
unwind_context,
kind,
- tcx.lang_items().oom().is_some(),
+ tcx.alloc_error_handler_kind(()).unwrap(),
tcx.sess.opts.unstable_opts.oom,
);
true
module: &mut impl Module,
unwind_context: &mut UnwindContext,
kind: AllocatorKind,
- has_alloc_error_handler: bool,
+ alloc_error_handler_kind: AllocatorKind,
oom_strategy: OomStrategy,
) {
let usize_ty = module.target_config().pointer_type();
returns: vec![],
};
- let callee_name = if has_alloc_error_handler { "__rg_oom" } else { "__rdl_oom" };
+ let callee_name = alloc_error_handler_kind.fn_name(sym::oom);
let func_id =
module.declare_function("__rust_alloc_error_handler", Linkage::Export, &sig).unwrap();
- let callee_func_id = module.declare_function(callee_name, Linkage::Import, &sig).unwrap();
+ let callee_func_id = module.declare_function(&callee_name, Linkage::Import, &sig).unwrap();
let mut ctx = Context::new();
ctx.func.signature = sig;
lval.write_cvalue(fx, CValue::by_val(operand, box_layout));
}
Rvalue::NullaryOp(null_op, ty) => {
- assert!(
- lval.layout()
- .ty
- .is_sized(fx.tcx.at(stmt.source_info.span), ParamEnv::reveal_all())
- );
+ assert!(lval.layout().ty.is_sized(fx.tcx, ParamEnv::reveal_all()));
let layout = fx.layout_of(fx.monomorphize(ty));
let val = match null_op {
NullOp::SizeOf => layout.size.bytes(),
use rustc_middle::mir::interpret::{
read_target_uint, AllocId, ConstAllocation, ConstValue, ErrorHandled, GlobalAlloc, Scalar,
};
-use rustc_span::DUMMY_SP;
use cranelift_module::*;
let is_mutable = if tcx.is_mutable_static(def_id) {
true
} else {
- !ty.is_freeze(tcx.at(DUMMY_SP), ParamEnv::reveal_all())
+ !ty.is_freeze(tcx, ParamEnv::reveal_all())
};
let align = tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap().align.pref.bytes();
use crate::GccContext;
-pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) {
+pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) {
let context = &mods.context;
let usize =
match tcx.sess.target.pointer_width {
.collect();
let func = context.new_function(None, FunctionType::Exported, void, &args, name, false);
- let kind =
- if has_alloc_error_handler {
- AllocatorKind::Global
- }
- else {
- AllocatorKind::Default
- };
- let callee = kind.fn_name(sym::oom);
+ let callee = alloc_error_handler_kind.fn_name(sym::oom);
let args: Vec<_> = types.iter().enumerate()
.map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
.collect();
}
impl ExtraBackendMethods for GccCodegenBackend {
- fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) -> Self::Module {
+ fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, module_name: &str, kind: AllocatorKind, alloc_error_handler_kind: AllocatorKind) -> Self::Module {
let mut mods = GccContext {
context: Context::default(),
};
- unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, has_alloc_error_handler); }
+ unsafe { allocator::codegen(tcx, &mut mods, module_name, kind, alloc_error_handler_kind); }
mods
}
fn val_ty(&self, value: RValue<'gcc>) -> Type<'gcc> {
value.get_type()
}
+
+ fn type_array(&self, ty: Type<'gcc>, mut len: u64) -> Type<'gcc> {
+ if let Some(struct_type) = ty.is_struct() {
+ if struct_type.get_field_count() == 0 {
+ // NOTE: since gccjit only supports i32 for the array size and libcore's tests uses a
+ // size of usize::MAX in test_binary_search, we workaround this by setting the size to
+ // zero for ZSTs.
+ // FIXME(antoyo): fix gccjit API.
+ len = 0;
+ }
+ }
+
+ // NOTE: see note above. Some other test uses usize::MAX.
+ if len == u64::MAX {
+ len = 0;
+ }
+
+ let len: i32 = len.try_into().expect("array len");
+
+ self.context.new_array_type(None, ty, len)
+ }
}
impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
self.context.new_opaque_struct_type(None, name)
}
- pub fn type_array(&self, ty: Type<'gcc>, mut len: u64) -> Type<'gcc> {
- if let Some(struct_type) = ty.is_struct() {
- if struct_type.get_field_count() == 0 {
- // NOTE: since gccjit only supports i32 for the array size and libcore's tests uses a
- // size of usize::MAX in test_binary_search, we workaround this by setting the size to
- // zero for ZSTs.
- // FIXME(antoyo): fix gccjit API.
- len = 0;
- }
- }
-
- // NOTE: see note above. Some other test uses usize::MAX.
- if len == u64::MAX {
- len = 0;
- }
-
- let len: i32 = len.try_into().expect("array len");
-
- self.context.new_array_type(None, ty, len)
- }
-
pub fn type_bool(&self) -> Type<'gcc> {
self.context.new_type::<bool>()
}
module_llvm: &mut ModuleLlvm,
module_name: &str,
kind: AllocatorKind,
- has_alloc_error_handler: bool,
+ alloc_error_handler_kind: AllocatorKind,
) {
let llcx = &*module_llvm.llcx;
let llmod = module_llvm.llmod();
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
}
- let kind = if has_alloc_error_handler { AllocatorKind::Global } else { AllocatorKind::Default };
- let callee = kind.fn_name(sym::oom);
+ let callee = alloc_error_handler_kind.fn_name(sym::oom);
let callee = llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
// -> ! DIFlagNoReturn
attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);
op_idx.insert(idx, constraints.len());
constraints.push(reg_to_llvm(reg, Some(&value.layout)));
}
- InlineAsmOperandRef::InOut { reg, late: _, in_value, out_place: _ } => {
+ InlineAsmOperandRef::InOut { reg, late, in_value, out_place: _ } => {
let value = llvm_fixup_input(
self,
in_value.immediate(),
&in_value.layout,
);
inputs.push(value);
- constraints.push(format!("{}", op_idx[&idx]));
+
+ // In the case of fixed registers, we have the choice of
+ // either using a tied operand or duplicating the constraint.
+ // We prefer the latter because it matches the behavior of
+ // Clang.
+ if late && matches!(reg, InlineAsmRegOrRegClass::Reg(_)) {
+ constraints.push(format!("{}", reg_to_llvm(reg, Some(&in_value.layout))));
+ } else {
+ constraints.push(format!("{}", op_idx[&idx]));
+ }
}
InlineAsmOperandRef::SymFn { instance } => {
inputs.push(self.cx.get_fn(instance));
let mut attrs = SmallVec::<[_; 2]>::new();
if options.contains(InlineAsmOptions::PURE) {
if options.contains(InlineAsmOptions::NOMEM) {
- attrs.push(llvm::AttributeKind::ReadNone.create_attr(self.cx.llcx));
+ attrs.push(llvm::MemoryEffects::None.create_attr(self.cx.llcx));
} else if options.contains(InlineAsmOptions::READONLY) {
- attrs.push(llvm::AttributeKind::ReadOnly.create_attr(self.cx.llcx));
+ attrs.push(llvm::MemoryEffects::ReadOnly.create_attr(self.cx.llcx));
}
attrs.push(llvm::AttributeKind::WillReturn.create_attr(self.cx.llcx));
} else if options.contains(InlineAsmOptions::NOMEM) {
- attrs.push(llvm::AttributeKind::InaccessibleMemOnly.create_attr(self.cx.llcx));
+ attrs.push(llvm::MemoryEffects::InaccessibleMemOnly.create_attr(self.cx.llcx));
} else {
// LLVM doesn't have an attribute to represent ReadOnly + SideEffect
}
}
}
+/// If the register is an AArch64 integer register then return its index.
+fn a64_reg_index(reg: InlineAsmReg) -> Option<u32> {
+ match reg {
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x0) => Some(0),
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x1) => Some(1),
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x2) => Some(2),
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x3) => Some(3),
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x4) => Some(4),
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x5) => Some(5),
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x6) => Some(6),
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x7) => Some(7),
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x8) => Some(8),
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x9) => Some(9),
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x10) => Some(10),
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x11) => Some(11),
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x12) => Some(12),
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x13) => Some(13),
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x14) => Some(14),
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x15) => Some(15),
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x16) => Some(16),
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x17) => Some(17),
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x18) => Some(18),
+ // x19 is reserved
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x20) => Some(20),
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x21) => Some(21),
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x22) => Some(22),
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x23) => Some(23),
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x24) => Some(24),
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x25) => Some(25),
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x26) => Some(26),
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x27) => Some(27),
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x28) => Some(28),
+ // x29 is reserved
+ InlineAsmReg::AArch64(AArch64InlineAsmReg::x30) => Some(30),
+ _ => None,
+ }
+}
+
/// If the register is an AArch64 vector register then return its index.
fn a64_vreg_index(reg: InlineAsmReg) -> Option<u32> {
match reg {
'x'
};
format!("{{{}mm{}}}", class, idx)
+ } else if let Some(idx) = a64_reg_index(reg) {
+ let class = if let Some(layout) = layout {
+ match layout.size.bytes() {
+ 8 => 'x',
+ _ => 'w',
+ }
+ } else {
+ // We use i32 as the type for discarded outputs
+ 'w'
+ };
+ if class == 'x' && reg == InlineAsmReg::AArch64(AArch64InlineAsmReg::x30) {
+ // LLVM doesn't recognize x30. use lr instead.
+ "{lr}".to_string()
+ } else {
+ format!("{{{}{}}}", class, idx)
+ }
} else if let Some(idx) = a64_vreg_index(reg) {
let class = if let Some(layout) = layout {
match layout.size.bytes() {
'q'
};
format!("{{{}{}}}", class, idx)
- } else if reg == InlineAsmReg::AArch64(AArch64InlineAsmReg::x30) {
- // LLVM doesn't recognize x30
- "{lr}".to_string()
} else if reg == InlineAsmReg::Arm(ArmInlineAsmReg::r14) {
// LLVM doesn't recognize r14
"{lr}".to_string()
use crate::attributes;
use crate::llvm::AttributePlace::Function;
-use crate::llvm::{self, AllocKindFlags, Attribute, AttributeKind, AttributePlace};
+use crate::llvm::{self, AllocKindFlags, Attribute, AttributeKind, AttributePlace, MemoryEffects};
use crate::llvm_util;
pub use rustc_attr::{InlineAttr, InstructionSetAttr, OptimizeAttr};
to_add.push(AttributeKind::ReturnsTwice.create_attr(cx.llcx));
}
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_PURE) {
- to_add.push(AttributeKind::ReadOnly.create_attr(cx.llcx));
+ to_add.push(MemoryEffects::ReadOnly.create_attr(cx.llcx));
}
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::FFI_CONST) {
- to_add.push(AttributeKind::ReadNone.create_attr(cx.llcx));
+ to_add.push(MemoryEffects::None.create_attr(cx.llcx));
}
if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
to_add.push(AttributeKind::Naked.create_attr(cx.llcx));
Int(I64) => "llvm.ssub.with.overflow.i64",
Int(I128) => "llvm.ssub.with.overflow.i128",
- Uint(U8) => "llvm.usub.with.overflow.i8",
- Uint(U16) => "llvm.usub.with.overflow.i16",
- Uint(U32) => "llvm.usub.with.overflow.i32",
- Uint(U64) => "llvm.usub.with.overflow.i64",
- Uint(U128) => "llvm.usub.with.overflow.i128",
+ Uint(_) => {
+ // Emit sub and icmp instead of llvm.usub.with.overflow. LLVM considers these
+ // to be the canonical form. It will attempt to reform llvm.usub.with.overflow
+ // in the backend if profitable.
+ let sub = self.sub(lhs, rhs);
+ let cmp = self.icmp(IntPredicate::IntULT, lhs, rhs);
+ return (sub, cmp);
+ }
_ => unreachable!(),
},
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, Instance, Ty};
use rustc_middle::{bug, span_bug};
+use rustc_session::config::Lto;
use rustc_target::abi::{
AddressSpace, Align, HasDataLayout, Primitive, Scalar, Size, WrappingRange,
};
// ThinLTO can't handle this workaround in all cases, so we don't
// emit the attrs. Instead we make them unnecessary by disallowing
// dynamic linking when linker plugin based LTO is enabled.
- !self.tcx.sess.opts.cg.linker_plugin_lto.enabled();
+ !self.tcx.sess.opts.cg.linker_plugin_lto.enabled() &&
+ self.tcx.sess.lto() != Lto::Thin;
// If this assertion triggers, there's something wrong with commandline
// argument validation.
if sess.target.arch == "s390x" {
target_data_layout = target_data_layout.replace("-v128:64", "");
}
+
+ if sess.target.arch == "riscv64" {
+ target_data_layout = target_data_layout.replace("-n32:64-", "-n64-");
+ }
}
// Ensure the data-layout values hardcoded remain the defaults.
tcx: TyCtxt<'tcx>,
module_name: &str,
kind: AllocatorKind,
- has_alloc_error_handler: bool,
+ alloc_error_handler_kind: AllocatorKind,
) -> ModuleLlvm {
let mut module_llvm = ModuleLlvm::new_metadata(tcx, module_name);
unsafe {
- allocator::codegen(tcx, &mut module_llvm, module_name, kind, has_alloc_error_handler);
+ allocator::codegen(tcx, &mut module_llvm, module_name, kind, alloc_error_handler_kind);
}
module_llvm
}
OptimizeNone = 24,
ReturnsTwice = 25,
ReadNone = 26,
- InaccessibleMemOnly = 27,
SanitizeHWAddress = 28,
WillReturn = 29,
StackProtectReq = 30,
SHA256,
}
+/// LLVMRustMemoryEffects
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub enum MemoryEffects {
+ None,
+ ReadOnly,
+ InaccessibleMemOnly,
+}
+
extern "C" {
type Opaque;
}
pub fn LLVMRustCreateUWTableAttr(C: &Context, async_: bool) -> &Attribute;
pub fn LLVMRustCreateAllocSizeAttr(C: &Context, size_arg: u32) -> &Attribute;
pub fn LLVMRustCreateAllocKindAttr(C: &Context, size_arg: u64) -> &Attribute;
+ pub fn LLVMRustCreateMemoryEffectsAttr(C: &Context, effects: MemoryEffects) -> &Attribute;
// Operations on functions
pub fn LLVMRustGetOrInsertFunction<'a>(
}
}
+impl MemoryEffects {
+ /// Create an LLVM Attribute with these memory effects.
+ pub fn create_attr(self, llcx: &Context) -> &Attribute {
+ unsafe { LLVMRustCreateMemoryEffectsAttr(llcx, self) }
+ }
+}
+
pub fn set_section(llglobal: &Value, section_name: &str) {
let section_name_cstr = CString::new(section_name).expect("unexpected CString error");
unsafe {
pub(crate) fn type_variadic_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type {
unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, True) }
}
-
- pub(crate) fn type_array(&self, ty: &'ll Type, len: u64) -> &'ll Type {
- unsafe { llvm::LLVMRustArrayType(ty, len) }
- }
}
impl<'ll, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
fn val_ty(&self, v: &'ll Value) -> &'ll Type {
common::val_ty(v)
}
+
+ fn type_array(&self, ty: &'ll Type, len: u64) -> &'ll Type {
+ unsafe { llvm::LLVMRustArrayType(ty, len) }
+ }
}
impl Type {
use object::read::archive::ArchiveFile;
-use std::fmt::Display;
use std::fs::File;
use std::io;
use std::path::{Path, PathBuf};
+use crate::errors::ExtractBundledLibsError;
+
pub trait ArchiveBuilderBuilder {
fn new_archive_builder<'a>(&self, sess: &'a Session) -> Box<dyn ArchiveBuilder<'a> + 'a>;
is_direct_dependency: bool,
) -> PathBuf;
- fn extract_bundled_libs(
- &self,
- rlib: &Path,
+ fn extract_bundled_libs<'a>(
+ &'a self,
+ rlib: &'a Path,
outdir: &Path,
bundled_lib_file_names: &FxHashSet<Symbol>,
- ) -> Result<(), String> {
- let message = |msg: &str, e: &dyn Display| format!("{} '{}': {}", msg, &rlib.display(), e);
+ ) -> Result<(), ExtractBundledLibsError<'_>> {
let archive_map = unsafe {
- Mmap::map(File::open(rlib).map_err(|e| message("failed to open file", &e))?)
- .map_err(|e| message("failed to mmap file", &e))?
+ Mmap::map(
+ File::open(rlib)
+ .map_err(|e| ExtractBundledLibsError::OpenFile { rlib, error: Box::new(e) })?,
+ )
+ .map_err(|e| ExtractBundledLibsError::MmapFile { rlib, error: Box::new(e) })?
};
let archive = ArchiveFile::parse(&*archive_map)
- .map_err(|e| message("failed to parse archive", &e))?;
+ .map_err(|e| ExtractBundledLibsError::ParseArchive { rlib, error: Box::new(e) })?;
for entry in archive.members() {
- let entry = entry.map_err(|e| message("failed to read entry", &e))?;
+ let entry = entry
+ .map_err(|e| ExtractBundledLibsError::ReadEntry { rlib, error: Box::new(e) })?;
let data = entry
.data(&*archive_map)
- .map_err(|e| message("failed to get data from archive member", &e))?;
+ .map_err(|e| ExtractBundledLibsError::ArchiveMember { rlib, error: Box::new(e) })?;
let name = std::str::from_utf8(entry.name())
- .map_err(|e| message("failed to convert name", &e))?;
+ .map_err(|e| ExtractBundledLibsError::ConvertName { rlib, error: Box::new(e) })?;
if !bundled_lib_file_names.contains(&Symbol::intern(name)) {
continue; // We need to extract only native libraries.
}
std::fs::write(&outdir.join(&name), data)
- .map_err(|e| message("failed to write file", &e))?;
+ .map_err(|e| ExtractBundledLibsError::WriteFile { rlib, error: Box::new(e) })?;
}
Ok(())
}
)
.is_some();
- sess.note_without_error("`link.exe` returned an unexpected error");
+ sess.emit_note(errors::LinkExeUnexpectedError);
if is_vs_installed && has_linker {
// the linker is broken
- sess.note_without_error(
- "the Visual Studio build tools may need to be repaired \
- using the Visual Studio installer",
- );
- sess.note_without_error(
- "or a necessary component may be missing from the \
- \"C++ build tools\" workload",
- );
+ sess.emit_note(errors::RepairVSBuildTools);
+ sess.emit_note(errors::MissingCppBuildToolComponent);
} else if is_vs_installed {
// the linker is not installed
- sess.note_without_error(
- "in the Visual Studio installer, ensure the \
- \"C++ build tools\" workload is selected",
- );
+ sess.emit_note(errors::SelectCppBuildToolWorkload);
} else {
// visual studio is not installed
- sess.note_without_error(
- "you may need to install Visual Studio build tools with the \
- \"C++ build tools\" workload",
- );
+ sess.emit_note(errors::VisualStudioNotInstalled);
}
}
}
Err(e) => {
let linker_not_found = e.kind() == io::ErrorKind::NotFound;
- let mut linker_error = {
- if linker_not_found {
- sess.struct_err(&format!("linker `{}` not found", linker_path.display()))
- } else {
- sess.struct_err(&format!(
- "could not exec the linker `{}`",
- linker_path.display()
- ))
- }
- };
-
- linker_error.note(&e.to_string());
-
- if !linker_not_found {
- linker_error.note(&format!("{:?}", &cmd));
+ if linker_not_found {
+ sess.emit_err(errors::LinkerNotFound { linker_path, error: e });
+ } else {
+ sess.emit_err(errors::UnableToExeLinker {
+ linker_path,
+ error: e,
+ command_formatted: format!("{:?}", &cmd),
+ });
}
- linker_error.emit();
-
if sess.target.is_like_msvc && linker_not_found {
- sess.note_without_error(
- "the msvc targets depend on the msvc linker \
- but `link.exe` was not found",
- );
- sess.note_without_error(
- "please ensure that Visual Studio 2017 or later, or Build Tools \
- for Visual Studio were installed with the Visual C++ option.",
- );
- sess.note_without_error("VS Code is a different product, and is not sufficient.");
+ sess.emit_note(errors::MsvcMissingLinker);
+ sess.emit_note(errors::CheckInstalledVisualStudio);
+ sess.emit_note(errors::UnsufficientVSCodeProduct);
}
sess.abort_if_errors();
}
if !prog.status.success() {
let mut output = prog.stderr.clone();
output.extend_from_slice(&prog.stdout);
- sess.struct_warn(&format!(
- "processing debug info with `dsymutil` failed: {}",
- prog.status
- ))
- .note(&escape_string(&output))
- .emit();
+ sess.emit_warning(errors::ProcessingDymutilFailed {
+ status: prog.status,
+ output: escape_string(&output),
+ });
}
}
- Err(e) => sess.fatal(&format!("unable to run `dsymutil`: {}", e)),
+ Err(error) => sess.emit_fatal(errors::UnableToRunDsymutil { error }),
}
}
if !prog.status.success() {
let mut output = prog.stderr.clone();
output.extend_from_slice(&prog.stdout);
- sess.struct_warn(&format!(
- "stripping debug info with `{}` failed: {}",
- util, prog.status
- ))
- .note(&escape_string(&output))
- .emit();
+ sess.emit_warning(errors::StrippingDebugInfoFailed {
+ util,
+ status: prog.status,
+ output: escape_string(&output),
+ });
}
}
- Err(e) => sess.fatal(&format!("unable to run `{}`: {}", util, e)),
+ Err(error) => sess.emit_fatal(errors::UnableToRun { util, error }),
}
}
if path.exists() {
return session_tlib;
} else {
- let default_sysroot = filesearch::get_or_default_sysroot();
+ let default_sysroot =
+ filesearch::get_or_default_sysroot().expect("Failed finding sysroot");
let default_tlib = filesearch::make_target_lib_path(
&default_sysroot,
sess.opts.target_triple.triple(),
)),
(Some(linker), None) => {
let stem = linker.file_stem().and_then(|stem| stem.to_str()).unwrap_or_else(|| {
- sess.fatal("couldn't extract file stem from specified linker")
+ sess.emit_fatal(errors::LinkerFileStem);
});
let flavor = if stem == "emcc" {
})
.collect();
if !lib_args.is_empty() {
- sess.note_without_error(
- "Link against the following native artifacts when linking \
- against this static library. The order and any duplication \
- can be significant on some platforms.",
- );
+ sess.emit_note(errors::StaticLibraryNativeArtifacts);
// Prefix for greppability
- sess.note_without_error(&format!("native-static-libs: {}", &lib_args.join(" ")));
+ sess.emit_note(errors::NativeStaticLibs { arguments: lib_args.join(" ") });
}
}
match (crate_type, &sess.target.link_script) {
(CrateType::Cdylib | CrateType::Executable, Some(script)) => {
if !sess.target.linker_flavor.is_gnu() {
- sess.fatal("can only use link script when linking with GNU-like linker");
+ sess.emit_fatal(errors::LinkScriptUnavailable);
}
let file_name = ["rustc", &sess.target.llvm_target, "linkfile.ld"].join("-");
let path = tmpdir.join(file_name);
- if let Err(e) = fs::write(&path, script.as_ref()) {
- sess.fatal(&format!("failed to write link script to {}: {}", path.display(), e));
+ if let Err(error) = fs::write(&path, script.as_ref()) {
+ sess.emit_fatal(errors::LinkScriptWriteFailure { path, error });
}
cmd.arg("--script");
let path = tmpdir.join("symbols.o");
let result = std::fs::write(&path, file.write().unwrap());
- if let Err(e) = result {
- sess.fatal(&format!("failed to write {}: {}", path.display(), e));
+ if let Err(error) = result {
+ sess.emit_fatal(errors::FailedToWrite { path, error });
}
cmd.add_object(&path);
}
visualizer_paths.push(visualizer_out_file);
}
Err(error) => {
- sess.warn(
- format!(
- "Unable to write debugger visualizer file `{}`: {} ",
- visualizer_out_file.display(),
- error
- )
- .as_str(),
- );
+ sess.emit_warning(errors::UnableToWriteDebuggerVisualizer {
+ path: visualizer_out_file,
+ error,
+ });
}
};
}
let rlib = &src.rlib.as_ref().unwrap().0;
archive_builder_builder
.extract_bundled_libs(rlib, tmpdir, &bundled_libs)
- .unwrap_or_else(|e| sess.fatal(e));
+ .unwrap_or_else(|e| sess.emit_fatal(e));
}
let mut last = (None, NativeLibKind::Unspecified, None);
|| !codegen_results.crate_info.is_no_builtins.contains(&cnum);
let mut archive = archive_builder_builder.new_archive_builder(sess);
- if let Err(e) = archive.add_archive(
+ if let Err(error) = archive.add_archive(
cratepath,
Box::new(move |f| {
if f == METADATA_FILENAME {
false
}),
) {
- sess.fatal(&format!("failed to build archive from rlib: {}", e));
+ sess.emit_fatal(errors::RlibArchiveBuildFailure { error });
}
if archive.build(&dst) {
link_upstream(&dst);
("arm", "watchos") => "watchos",
(_, "macos") => "macosx",
_ => {
- sess.err(&format!("unsupported arch `{}` for os `{}`", arch, os));
+ sess.emit_err(errors::UnsupportedArch { arch, os });
return;
}
};
let sdk_root = match get_apple_sdk_root(sdk_name) {
Ok(s) => s,
Err(e) => {
- sess.err(&e);
+ sess.emit_err(e);
return;
}
};
}
}
-fn get_apple_sdk_root(sdk_name: &str) -> Result<String, String> {
+fn get_apple_sdk_root(sdk_name: &str) -> Result<String, errors::AppleSdkRootError<'_>> {
// Following what clang does
// (https://github.com/llvm/llvm-project/blob/
// 296a80102a9b72c3eda80558fb78a3ed8849b341/clang/lib/Driver/ToolChains/Darwin.cpp#L1661-L1678)
match res {
Ok(output) => Ok(output.trim().to_string()),
- Err(e) => Err(format!("failed to get {} SDK path: {}", sdk_name, e)),
+ Err(error) => Err(errors::AppleSdkRootError::SdkPath { sdk_name, error }),
}
}
}
}
} else {
- sess.fatal("option `-Z gcc-ld` is used even though linker flavor is not gcc");
+ sess.emit_fatal(errors::OptionGccOnly);
}
}
}
}
if tcx.allocator_kind(()).is_some() {
- for method in ALLOCATOR_METHODS {
- let symbol_name = format!("__rust_{}", method.name);
+ for symbol_name in ALLOCATOR_METHODS
+ .iter()
+ .map(|method| format!("__rust_{}", method.name))
+ .chain(["__rust_alloc_error_handler".to_string(), OomStrategy::SYMBOL.to_string()])
+ {
let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(tcx, &symbol_name));
symbols.push((
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_hir::lang_items::LangItem;
-use rustc_hir::weak_lang_items::WEAK_ITEMS_SYMBOLS;
use rustc_index::vec::Idx;
use rustc_metadata::EncodedMetadata;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
let llmod_id =
cgu_name_builder.build_cgu_name(LOCAL_CRATE, &["crate"], Some("allocator")).to_string();
let module_llvm = tcx.sess.time("write_allocator_module", || {
- backend.codegen_allocator(tcx, &llmod_id, kind, tcx.lang_items().oom().is_some())
+ backend.codegen_allocator(
+ tcx,
+ &llmod_id,
+ kind,
+ // If allocator_kind is Some then alloc_error_handler_kind must
+ // also be Some.
+ tcx.alloc_error_handler_kind(()).unwrap(),
+ )
});
Some(ModuleCodegen { name: llmod_id, module_llvm, kind: ModuleKind::Allocator })
// by the compiler, but that's ok because all this stuff is unstable anyway.
let target = &tcx.sess.target;
if !are_upstream_rust_objects_already_included(tcx.sess) {
- let missing_weak_lang_items: FxHashSet<&Symbol> = info
+ let missing_weak_lang_items: FxHashSet<Symbol> = info
.used_crates
.iter()
- .flat_map(|cnum| {
- tcx.missing_lang_items(*cnum)
- .iter()
- .filter(|l| lang_items::required(tcx, **l))
- .filter_map(|item| WEAK_ITEMS_SYMBOLS.get(item))
+ .flat_map(|&cnum| tcx.missing_lang_items(cnum))
+ .filter(|l| l.is_weak())
+ .filter_map(|&l| {
+ let name = l.link_name()?;
+ lang_items::required(tcx, l).then_some(name)
})
.collect();
let prefix = if target.is_like_windows && target.arch == "x86" { "_" } else { "" };
match *t.kind() {
ty::Bool => output.push_str("bool"),
ty::Char => output.push_str("char"),
- ty::Str => output.push_str("str"),
+ ty::Str => {
+ if cpp_like_debuginfo {
+ output.push_str("str$")
+ } else {
+ output.push_str("str")
+ }
+ }
ty::Never => {
if cpp_like_debuginfo {
output.push_str("never$");
}
}
ty::Ref(_, inner_type, mutbl) => {
- // Slices and `&str` are treated like C++ pointers when computing debug
- // info for MSVC debugger. However, wrapping these types' names in a synthetic type
- // causes the .natvis engine for WinDbg to fail to display their data, so we opt these
- // types out to aid debugging in MSVC.
- let is_slice_or_str = matches!(*inner_type.kind(), ty::Slice(_) | ty::Str);
-
- if !cpp_like_debuginfo {
- output.push('&');
- output.push_str(mutbl.prefix_str());
- } else if !is_slice_or_str {
+ if cpp_like_debuginfo {
match mutbl {
Mutability::Not => output.push_str("ref$<"),
Mutability::Mut => output.push_str("ref_mut$<"),
}
+ } else {
+ output.push('&');
+ output.push_str(mutbl.prefix_str());
}
push_debuginfo_type_name(tcx, inner_type, qualified, output, visited);
- if cpp_like_debuginfo && !is_slice_or_str {
+ if cpp_like_debuginfo {
push_close_angle_bracket(cpp_like_debuginfo, output);
}
}
}
ty::Slice(inner_type) => {
if cpp_like_debuginfo {
- output.push_str("slice$<");
+ output.push_str("slice2$<");
} else {
output.push('[');
}
diag
}
}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_link_exe_unexpected_error)]
+pub struct LinkExeUnexpectedError;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_repair_vs_build_tools)]
+pub struct RepairVSBuildTools;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_missing_cpp_build_tool_component)]
+pub struct MissingCppBuildToolComponent;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_select_cpp_build_tool_workload)]
+pub struct SelectCppBuildToolWorkload;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_visual_studio_not_installed)]
+pub struct VisualStudioNotInstalled;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_linker_not_found)]
+#[note]
+pub struct LinkerNotFound {
+ pub linker_path: PathBuf,
+ pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_unable_to_exe_linker)]
+#[note]
+#[note(command_note)]
+pub struct UnableToExeLinker {
+ pub linker_path: PathBuf,
+ pub error: Error,
+ pub command_formatted: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_msvc_missing_linker)]
+pub struct MsvcMissingLinker;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_check_installed_visual_studio)]
+pub struct CheckInstalledVisualStudio;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_unsufficient_vs_code_product)]
+pub struct UnsufficientVSCodeProduct;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_processing_dymutil_failed)]
+#[note]
+pub struct ProcessingDymutilFailed {
+ pub status: ExitStatus,
+ pub output: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_unable_to_run_dsymutil)]
+#[note]
+pub struct UnableToRunDsymutil {
+ pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_stripping_debu_info_failed)]
+#[note]
+pub struct StrippingDebugInfoFailed<'a> {
+ pub util: &'a str,
+ pub status: ExitStatus,
+ pub output: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_unable_to_run)]
+pub struct UnableToRun<'a> {
+ pub util: &'a str,
+ pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_linker_file_stem)]
+pub struct LinkerFileStem;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_static_library_native_artifacts)]
+pub struct StaticLibraryNativeArtifacts;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_native_static_libs)]
+pub struct NativeStaticLibs {
+ pub arguments: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_link_script_unavailable)]
+pub struct LinkScriptUnavailable;
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_link_script_write_failure)]
+pub struct LinkScriptWriteFailure {
+ pub path: PathBuf,
+ pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_failed_to_write)]
+pub struct FailedToWrite {
+ pub path: PathBuf,
+ pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_unable_to_write_debugger_visualizer)]
+pub struct UnableToWriteDebuggerVisualizer {
+ pub path: PathBuf,
+ pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_rlib_archive_build_failure)]
+pub struct RlibArchiveBuildFailure {
+ pub error: Error,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_option_gcc_only)]
+pub struct OptionGccOnly;
+
+#[derive(Diagnostic)]
+pub enum ExtractBundledLibsError<'a> {
+ #[diag(codegen_ssa_extract_bundled_libs_open_file)]
+ OpenFile { rlib: &'a Path, error: Box<dyn std::error::Error> },
+
+ #[diag(codegen_ssa_extract_bundled_libs_mmap_file)]
+ MmapFile { rlib: &'a Path, error: Box<dyn std::error::Error> },
+
+ #[diag(codegen_ssa_extract_bundled_libs_parse_archive)]
+ ParseArchive { rlib: &'a Path, error: Box<dyn std::error::Error> },
+
+ #[diag(codegen_ssa_extract_bundled_libs_read_entry)]
+ ReadEntry { rlib: &'a Path, error: Box<dyn std::error::Error> },
+
+ #[diag(codegen_ssa_extract_bundled_libs_archive_member)]
+ ArchiveMember { rlib: &'a Path, error: Box<dyn std::error::Error> },
+
+ #[diag(codegen_ssa_extract_bundled_libs_convert_name)]
+ ConvertName { rlib: &'a Path, error: Box<dyn std::error::Error> },
+
+ #[diag(codegen_ssa_extract_bundled_libs_write_file)]
+ WriteFile { rlib: &'a Path, error: Box<dyn std::error::Error> },
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_unsupported_arch)]
+pub struct UnsupportedArch<'a> {
+ pub arch: &'a str,
+ pub os: &'a str,
+}
+
+#[derive(Diagnostic)]
+pub enum AppleSdkRootError<'a> {
+ #[diag(codegen_ssa_apple_sdk_error_sdk_path)]
+ SdkPath { sdk_name: &'a str, error: Error },
+}
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
use rustc_middle::ty::{self, Instance, Ty, TypeVisitable};
+use rustc_session::config::OptLevel;
use rustc_span::source_map::Span;
use rustc_span::{sym, Symbol};
use rustc_symbol_mangling::typeid::typeid_for_fnabi;
assert_eq!(discr.layout.ty, switch_ty);
let mut target_iter = targets.iter();
if target_iter.len() == 1 {
- // If there are two targets (one conditional, one fallback), emit br instead of switch
+ // If there are two targets (one conditional, one fallback), emit `br` instead of
+ // `switch`.
let (test_value, target) = target_iter.next().unwrap();
let lltrue = helper.llbb_with_cleanup(self, target);
let llfalse = helper.llbb_with_cleanup(self, targets.otherwise());
if switch_ty == bx.tcx().types.bool {
- // Don't generate trivial icmps when switching on bool
+ // Don't generate trivial icmps when switching on bool.
match test_value {
0 => bx.cond_br(discr.immediate(), llfalse, lltrue),
1 => bx.cond_br(discr.immediate(), lltrue, llfalse),
let cmp = bx.icmp(IntPredicate::IntEQ, discr.immediate(), llval);
bx.cond_br(cmp, lltrue, llfalse);
}
+ } else if self.cx.sess().opts.optimize == OptLevel::No
+ && target_iter.len() == 2
+ && self.mir[targets.otherwise()].is_empty_unreachable()
+ {
+ // In unoptimized builds, if there are two normal targets and the `otherwise` target is
+ // an unreachable BB, emit `br` instead of `switch`. This leaves behind the unreachable
+ // BB, which will usually (but not always) be dead code.
+ //
+ // Why only in unoptimized builds?
+ // - In unoptimized builds LLVM uses FastISel which does not support switches, so it
+ // must fall back to the to the slower SelectionDAG isel. Therefore, using `br` gives
+ // significant compile time speedups for unoptimized builds.
+ // - In optimized builds the above doesn't hold, and using `br` sometimes results in
+ // worse generated code because LLVM can no longer tell that the value being switched
+ // on can only have two values, e.g. 0 and 1.
+ //
+ let (test_value1, target1) = target_iter.next().unwrap();
+ let (_test_value2, target2) = target_iter.next().unwrap();
+ let ll1 = helper.llbb_with_cleanup(self, target1);
+ let ll2 = helper.llbb_with_cleanup(self, target2);
+ let switch_llty = bx.immediate_backend_type(bx.layout_of(switch_ty));
+ let llval = bx.const_uint_big(switch_llty, test_value1);
+ let cmp = bx.icmp(IntPredicate::IntEQ, discr.immediate(), llval);
+ bx.cond_br(cmp, ll1, ll2);
} else {
bx.switch(
discr.immediate(),
// tidy-alphabetical-start
("atomics", Some(sym::wasm_target_feature)),
("bulk-memory", Some(sym::wasm_target_feature)),
+ ("multivalue", Some(sym::wasm_target_feature)),
("mutable-globals", Some(sym::wasm_target_feature)),
("nontrapping-fptoint", Some(sym::wasm_target_feature)),
("reference-types", Some(sym::wasm_target_feature)),
tcx: TyCtxt<'tcx>,
module_name: &str,
kind: AllocatorKind,
- has_alloc_error_handler: bool,
+ alloc_error_handler_kind: AllocatorKind,
) -> Self::Module;
/// This generates the codegen unit and returns it along with
/// a `u64` giving an estimate of the unit's processing cost.
use crate::mir::place::PlaceRef;
use rustc_middle::ty::layout::TyAndLayout;
use rustc_middle::ty::{self, Ty};
-use rustc_span::DUMMY_SP;
use rustc_target::abi::call::{ArgAbi, CastTarget, FnAbi, Reg};
use rustc_target::abi::{AddressSpace, Integer};
fn type_f32(&self) -> Self::Type;
fn type_f64(&self) -> Self::Type;
+ fn type_array(&self, ty: Self::Type, len: u64) -> Self::Type;
fn type_func(&self, args: &[Self::Type], ret: Self::Type) -> Self::Type;
fn type_struct(&self, els: &[Self::Type], packed: bool) -> Self::Type;
fn type_kind(&self, ty: Self::Type) -> TypeKind;
}
fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
- ty.is_sized(self.tcx().at(DUMMY_SP), ty::ParamEnv::reveal_all())
+ ty.is_sized(self.tcx(), ty::ParamEnv::reveal_all())
}
fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
- ty.is_freeze(self.tcx().at(DUMMY_SP), ty::ParamEnv::reveal_all())
+ ty.is_freeze(self.tcx(), ty::ParamEnv::reveal_all())
}
fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool {
let param_env = ty::ParamEnv::reveal_all();
- if ty.is_sized(self.tcx().at(DUMMY_SP), param_env) {
+ if ty.is_sized(self.tcx(), param_env) {
return false;
}
use rustc_middle::mir;
use rustc_middle::ty::{self, Ty, TyCtxt};
use std::borrow::Borrow;
-use std::collections::hash_map::Entry;
use std::hash::Hash;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxIndexMap;
+use rustc_data_structures::fx::IndexEntry;
use std::fmt;
use rustc_ast::Mutability;
}
}
-impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxHashMap<K, V> {
+impl<K: Hash + Eq, V> interpret::AllocMap<K, V> for FxIndexMap<K, V> {
#[inline(always)]
fn contains_key<Q: ?Sized + Hash + Eq>(&mut self, k: &Q) -> bool
where
K: Borrow<Q>,
{
- FxHashMap::contains_key(self, k)
+ FxIndexMap::contains_key(self, k)
}
#[inline(always)]
fn insert(&mut self, k: K, v: V) -> Option<V> {
- FxHashMap::insert(self, k, v)
+ FxIndexMap::insert(self, k, v)
}
#[inline(always)]
where
K: Borrow<Q>,
{
- FxHashMap::remove(self, k)
+ FxIndexMap::remove(self, k)
}
#[inline(always)]
#[inline(always)]
fn get_mut_or<E>(&mut self, k: K, vacant: impl FnOnce() -> Result<V, E>) -> Result<&mut V, E> {
match self.entry(k) {
- Entry::Occupied(e) => Ok(e.into_mut()),
- Entry::Vacant(e) => {
+ IndexEntry::Occupied(e) => Ok(e.into_mut()),
+ IndexEntry::Vacant(e) => {
let v = vacant()?;
Ok(e.insert(v))
}
) -> MPlaceTy<'tcx> {
let tcx = ecx.tcx.tcx;
- if !ty.is_sized(ecx.tcx, ty::ParamEnv::empty()) {
+ if !ty.is_sized(*ecx.tcx, ty::ParamEnv::empty()) {
// We need to create `Allocation`s for custom DSTs
let (unsized_inner_ty, num_elems) = get_info_on_unsized_field(ty, valtree, tcx);
let mut place_inner = match ty.kind() {
ty::Str | ty::Slice(_) => ecx.mplace_index(&place, i as u64).unwrap(),
- _ if !ty.is_sized(ecx.tcx, ty::ParamEnv::empty())
+ _ if !ty.is_sized(*ecx.tcx, ty::ParamEnv::empty())
&& i == branches.len() - 1 =>
{
// Note: For custom DSTs we need to manually process the last unsized field.
#[inline]
pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
- ty.is_freeze(self.tcx, self.param_env)
+ ty.is_freeze(*self.tcx, self.param_env)
}
pub fn load_mir(
// the last field). Can't have foreign types here, how would we
// adjust alignment and size for them?
let field = layout.field(self, layout.fields.count() - 1);
- let Some((unsized_size, unsized_align)) = self.size_and_align_of(metadata, &field)? else {
+ let Some((unsized_size, mut unsized_align)) = self.size_and_align_of(metadata, &field)? else {
// A field with an extern type. We don't know the actual dynamic size
// or the alignment.
return Ok(None);
// Return the sum of sizes and max of aligns.
let size = sized_size + unsized_size; // `Size` addition
+ // Packed types ignore the alignment of their fields.
+ if let ty::Adt(def, _) = layout.ty.kind() {
+ if def.repr().packed() {
+ unsized_align = sized_align;
+ }
+ }
+
// Choose max of two known alignments (combined value must
// be aligned according to more restrictive of the two).
let align = sized_align.max(unsized_align);
//! that contains allocations whose mutability we cannot identify.)
use super::validity::RefTracking;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_middle::mir::interpret::InterpResult;
ExtraFnVal = !,
FrameExtra = (),
AllocExtra = (),
- MemoryMap = FxHashMap<AllocId, (MemoryKind<T>, Allocation)>,
+ MemoryMap = FxIndexMap<AllocId, (MemoryKind<T>, Allocation)>,
>;
struct InternVisitor<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>> {
ref_tracking: &'rt mut RefTracking<(MPlaceTy<'tcx>, InternMode)>,
/// A list of all encountered allocations. After type-based interning, we traverse this list to
/// also intern allocations that are only referenced by a raw pointer or inside a union.
- leftover_allocations: &'rt mut FxHashSet<AllocId>,
+ leftover_allocations: &'rt mut FxIndexSet<AllocId>,
/// The root kind of the value that we're looking at. This field is never mutated for a
/// particular allocation. It is primarily used to make as many allocations as possible
/// read-only so LLVM can place them in const memory.
/// to account for (e.g. for vtables).
fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval::MemoryKind>>(
ecx: &'rt mut InterpCx<'mir, 'tcx, M>,
- leftover_allocations: &'rt mut FxHashSet<AllocId>,
+ leftover_allocations: &'rt mut FxIndexSet<AllocId>,
alloc_id: AllocId,
mode: InternMode,
ty: Option<Ty<'tcx>>,
if let InternMode::Static(mutability) = mode {
// For this, we need to take into account `UnsafeCell`. When `ty` is `None`, we assume
// no interior mutability.
- let frozen = ty.map_or(true, |ty| ty.is_freeze(ecx.tcx, ecx.param_env));
+ let frozen = ty.map_or(true, |ty| ty.is_freeze(*ecx.tcx, ecx.param_env));
// For statics, allocation mutability is the combination of place mutability and
// type mutability.
// The entire allocation needs to be mutable if it contains an `UnsafeCell` anywhere.
// `leftover_allocations` collects *all* allocations we see, because some might not
// be available in a typed way. They get interned at the end.
let mut ref_tracking = RefTracking::empty();
- let leftover_allocations = &mut FxHashSet::default();
+ let leftover_allocations = &mut FxIndexSet::default();
// start with the outermost allocation
intern_shallow(
use rustc_hir::def_id::DefId;
use rustc_middle::mir::{
self,
- interpret::{ConstValue, GlobalId, InterpResult, PointerArithmetic, Scalar},
+ interpret::{
+ Allocation, ConstAllocation, ConstValue, GlobalId, InterpResult, PointerArithmetic, Scalar,
+ },
BinOp, NonDivergingIntrinsic,
};
use rustc_middle::ty;
};
mod caller_location;
-mod type_name;
fn numeric_intrinsic<Prov>(name: Symbol, bits: u128, kind: Primitive) -> Scalar<Prov> {
let size = match kind {
Scalar::from_uint(bits_out, size)
}
+/// Directly returns an `Allocation` containing an absolute path representation of the given type.
+pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAllocation<'tcx> {
+ let path = crate::util::type_name(tcx, ty);
+ let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes());
+ tcx.intern_const_alloc(alloc)
+}
+
/// The logic for all nullary intrinsics is implemented here. These intrinsics don't get evaluated
/// inside an `InterpCx` and instead have their value computed directly from rustc internal info.
pub(crate) fn eval_nullary_intrinsic<'tcx>(
Ok(match name {
sym::type_name => {
ensure_monomorphic_enough(tcx, tp_ty)?;
- let alloc = type_name::alloc_type_name(tcx, tp_ty);
+ let alloc = alloc_type_name(tcx, tp_ty);
ConstValue::Slice { data: alloc, start: 0, end: alloc.inner().len() }
}
sym::needs_drop => {
+++ /dev/null
-use rustc_data_structures::intern::Interned;
-use rustc_hir::def_id::CrateNum;
-use rustc_hir::definitions::DisambiguatedDefPathData;
-use rustc_middle::mir::interpret::{Allocation, ConstAllocation};
-use rustc_middle::ty::{
- self,
- print::{with_no_verbose_constants, PrettyPrinter, Print, Printer},
- subst::{GenericArg, GenericArgKind},
- Ty, TyCtxt,
-};
-use std::fmt::Write;
-
-struct AbsolutePathPrinter<'tcx> {
- tcx: TyCtxt<'tcx>,
- path: String,
-}
-
-impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
- type Error = std::fmt::Error;
-
- type Path = Self;
- type Region = Self;
- type Type = Self;
- type DynExistential = Self;
- type Const = Self;
-
- fn tcx(&self) -> TyCtxt<'tcx> {
- self.tcx
- }
-
- fn print_region(self, _region: ty::Region<'_>) -> Result<Self::Region, Self::Error> {
- Ok(self)
- }
-
- fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
- match *ty.kind() {
- // Types without identity.
- ty::Bool
- | ty::Char
- | ty::Int(_)
- | ty::Uint(_)
- | ty::Float(_)
- | ty::Str
- | ty::Array(_, _)
- | ty::Slice(_)
- | ty::RawPtr(_)
- | ty::Ref(_, _, _)
- | ty::FnPtr(_)
- | ty::Never
- | ty::Tuple(_)
- | ty::Dynamic(_, _, _) => self.pretty_print_type(ty),
-
- // Placeholders (all printed as `_` to uniformize them).
- ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => {
- write!(self, "_")?;
- Ok(self)
- }
-
- // Types with identity (print the module path).
- ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), substs)
- | ty::FnDef(def_id, substs)
- | ty::Opaque(def_id, substs)
- | ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs })
- | ty::Closure(def_id, substs)
- | ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs),
- ty::Foreign(def_id) => self.print_def_path(def_id, &[]),
-
- ty::GeneratorWitness(_) => bug!("type_name: unexpected `GeneratorWitness`"),
- }
- }
-
- fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
- self.pretty_print_const(ct, false)
- }
-
- fn print_dyn_existential(
- mut self,
- predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
- ) -> Result<Self::DynExistential, Self::Error> {
- let mut first = true;
- for p in predicates {
- if !first {
- write!(self, "+")?;
- }
- first = false;
- self = p.print(self)?;
- }
- Ok(self)
- }
-
- fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
- self.path.push_str(self.tcx.crate_name(cnum).as_str());
- Ok(self)
- }
-
- fn path_qualified(
- self,
- self_ty: Ty<'tcx>,
- trait_ref: Option<ty::TraitRef<'tcx>>,
- ) -> Result<Self::Path, Self::Error> {
- self.pretty_path_qualified(self_ty, trait_ref)
- }
-
- fn path_append_impl(
- self,
- print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
- _disambiguated_data: &DisambiguatedDefPathData,
- self_ty: Ty<'tcx>,
- trait_ref: Option<ty::TraitRef<'tcx>>,
- ) -> Result<Self::Path, Self::Error> {
- self.pretty_path_append_impl(
- |mut cx| {
- cx = print_prefix(cx)?;
-
- cx.path.push_str("::");
-
- Ok(cx)
- },
- self_ty,
- trait_ref,
- )
- }
-
- fn path_append(
- mut self,
- print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
- disambiguated_data: &DisambiguatedDefPathData,
- ) -> Result<Self::Path, Self::Error> {
- self = print_prefix(self)?;
-
- write!(self.path, "::{}", disambiguated_data.data).unwrap();
-
- Ok(self)
- }
-
- fn path_generic_args(
- mut self,
- print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
- args: &[GenericArg<'tcx>],
- ) -> Result<Self::Path, Self::Error> {
- self = print_prefix(self)?;
- let args =
- args.iter().cloned().filter(|arg| !matches!(arg.unpack(), GenericArgKind::Lifetime(_)));
- if args.clone().next().is_some() {
- self.generic_delimiters(|cx| cx.comma_sep(args))
- } else {
- Ok(self)
- }
- }
-}
-
-impl<'tcx> PrettyPrinter<'tcx> for AbsolutePathPrinter<'tcx> {
- fn should_print_region(&self, _region: ty::Region<'_>) -> bool {
- false
- }
- fn comma_sep<T>(mut self, mut elems: impl Iterator<Item = T>) -> Result<Self, Self::Error>
- where
- T: Print<'tcx, Self, Output = Self, Error = Self::Error>,
- {
- if let Some(first) = elems.next() {
- self = first.print(self)?;
- for elem in elems {
- self.path.push_str(", ");
- self = elem.print(self)?;
- }
- }
- Ok(self)
- }
-
- fn generic_delimiters(
- mut self,
- f: impl FnOnce(Self) -> Result<Self, Self::Error>,
- ) -> Result<Self, Self::Error> {
- write!(self, "<")?;
-
- self = f(self)?;
-
- write!(self, ">")?;
-
- Ok(self)
- }
-}
-
-impl Write for AbsolutePathPrinter<'_> {
- fn write_str(&mut self, s: &str) -> std::fmt::Result {
- self.path.push_str(s);
- Ok(())
- }
-}
-
-/// Directly returns an `Allocation` containing an absolute path representation of the given type.
-pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> ConstAllocation<'tcx> {
- let path = with_no_verbose_constants!(
- AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path
- );
- let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes());
- tcx.intern_const_alloc(alloc)
-}
type ExtraFnVal = !;
type MemoryMap =
- rustc_data_structures::fx::FxHashMap<AllocId, (MemoryKind<Self::MemoryKind>, Allocation)>;
+ rustc_data_structures::fx::FxIndexMap<AllocId, (MemoryKind<Self::MemoryKind>, Allocation)>;
const GLOBAL_KIND: Option<Self::MemoryKind> = None; // no copying of globals from `tcx` to machine memory
type AllocExtra = ();
use rustc_hir::def::Namespace;
use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt, TyAndLayout};
use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
-use rustc_middle::ty::{ConstInt, DelaySpanBugEmitted, Ty};
+use rustc_middle::ty::{ConstInt, Ty};
use rustc_middle::{mir, ty};
use rustc_target::abi::{self, Abi, Align, HasDataLayout, Size, TagEncoding};
use rustc_target::abi::{VariantIdx, Variants};
ty::ConstKind::Param(_) | ty::ConstKind::Placeholder(..) => {
throw_inval!(TooGeneric)
}
- ty::ConstKind::Error(DelaySpanBugEmitted { reported, .. }) => {
+ ty::ConstKind::Error(reported) => {
throw_inval!(AlreadyReported(reported))
}
ty::ConstKind::Unevaluated(uv) => {
use rustc_middle::ty;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
use rustc_span::symbol::{sym, Symbol};
-use rustc_span::DUMMY_SP;
use rustc_target::abi::{Abi, Scalar as ScalarAbi, Size, VariantIdx, Variants, WrappingRange};
use std::hash::Hash;
) -> InterpResult<'tcx> {
// Special check preventing `UnsafeCell` inside unions in the inner part of constants.
if matches!(self.ctfe_mode, Some(CtfeValidationMode::Const { inner: true, .. })) {
- if !op.layout.ty.is_freeze(self.ecx.tcx.at(DUMMY_SP), self.ecx.param_env) {
+ if !op.layout.ty.is_freeze(*self.ecx.tcx, self.ecx.param_env) {
throw_validation_failure!(self.path, { "`UnsafeCell` in a `const`" });
}
}
#![feature(yeet_expr)]
#![feature(is_some_and)]
#![recursion_limit = "256"]
-#![allow(rustc::potential_query_instability)]
#[macro_use]
extern crate tracing;
use rustc_middle::ty::{Binder, TraitPredicate, TraitRef, TypeVisitable};
use rustc_mir_dataflow::{self, Analysis};
use rustc_span::{sym, Span, Symbol};
-use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
-use rustc_trait_selection::traits::{
- self, ObligationCauseCode, SelectionContext, TraitEngine, TraitEngineExt,
-};
+use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt, SelectionContext};
use std::mem;
use std::ops::Deref;
// "non-const" check. This is required for correctness here.
{
let infcx = tcx.infer_ctxt().build();
- let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
+ let ocx = ObligationCtxt::new(&infcx);
+
let predicates = tcx.predicates_of(callee).instantiate(tcx, substs);
let hir_id = tcx
.hir()
.local_def_id_to_hir_id(self.body.source.def_id().expect_local());
- let cause = || {
- ObligationCause::new(
- terminator.source_info.span,
- hir_id,
- ObligationCauseCode::ItemObligation(callee),
- )
- };
- let normalized = infcx.partially_normalize_associated_types_in(
- cause(),
- param_env,
- predicates,
+ let cause = ObligationCause::new(
+ terminator.source_info.span,
+ hir_id,
+ ObligationCauseCode::ItemObligation(callee),
);
-
- for p in normalized.obligations {
- fulfill_cx.register_predicate_obligation(&infcx, p);
- }
- for obligation in traits::predicates_for_generics(
- |_, _| cause(),
+ let normalized_predicates =
+ ocx.normalize(cause.clone(), param_env, predicates);
+ ocx.register_obligations(traits::predicates_for_generics(
+ |_, _| cause.clone(),
self.param_env,
- normalized.value,
- ) {
- fulfill_cx.register_predicate_obligation(&infcx, obligation);
- }
- let errors = fulfill_cx.select_all_or_error(&infcx);
+ normalized_predicates,
+ ));
+
+ let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None);
}
}
obligation.clone(),
&obligation,
&e,
- false,
);
}
use rustc_middle::mir;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty};
-use rustc_span::DUMMY_SP;
use rustc_trait_selection::traits::{
self, ImplSource, Obligation, ObligationCause, SelectionContext,
};
}
fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
- !ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env)
+ !ty.is_freeze(cx.tcx, cx.param_env)
}
fn in_adt_inherently<'tcx>(
qualifs.needs_non_const_drop
}
+ #[instrument(level = "trace", skip(cx), ret)]
fn in_any_value_of_ty<'tcx>(cx: &ConstCx<'_, 'tcx>, ty: Ty<'tcx>) -> bool {
// Avoid selecting for simple cases, such as builtin types.
if ty::util::is_trivially_const_drop(ty) {
return true;
};
+ trace!(?impl_src);
+
if !matches!(
impl_src,
ImplSource::ConstDestruct(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
use rustc_mir_dataflow::fmt::DebugWithContext;
use rustc_mir_dataflow::JoinSemiLattice;
use rustc_mir_dataflow::{Analysis, AnalysisDomain, CallReturnPlaces};
-use rustc_span::DUMMY_SP;
use std::fmt;
use std::marker::PhantomData;
///
/// [rust-lang/unsafe-code-guidelines#134]: https://github.com/rust-lang/unsafe-code-guidelines/issues/134
fn shared_borrow_allows_mutation(&self, place: mir::Place<'tcx>) -> bool {
- !place
- .ty(self.ccx.body, self.ccx.tcx)
- .ty
- .is_freeze(self.ccx.tcx.at(DUMMY_SP), self.ccx.param_env)
+ !place.ty(self.ccx.body, self.ccx.tcx).ty.is_freeze(self.ccx.tcx, self.ccx.param_env)
}
}
// There's not really any point in promoting errorful MIR.
//
// This does not include MIR that failed const-checking, which we still try to promote.
- if body.return_ty().references_error() {
- tcx.sess.delay_span_bug(body.span, "PromoteTemps: MIR had errors");
+ if let Err(_) = body.return_ty().error_reported() {
+ debug!("PromoteTemps: MIR had errors");
return;
}
-
if body.source.promoted.is_some() {
return;
}
// `Operand::Copy` is only supposed to be used with `Copy` types.
if let Operand::Copy(place) = operand {
let ty = place.ty(&self.body.local_decls, self.tcx).ty;
- let span = self.body.source_info(location).span;
- if !ty.is_copy_modulo_regions(self.tcx.at(span), self.param_env) {
+ if !ty.is_copy_modulo_regions(self.tcx, self.param_env) {
self.fail(location, format!("`Operand::Copy` with non-`Copy` type {}", ty));
}
}
//! context.
use rustc_hir::def_id::DefId;
-use rustc_hir::lang_items::LangItemGroup;
+use rustc_hir::lang_items;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, AssocItemContainer, DefIdTree, Instance, ParamEnv, Ty, TyCtxt};
use rustc_span::symbol::Ident;
}
});
- let fn_call = parent
- .and_then(|p| tcx.lang_items().group(LangItemGroup::Fn).iter().find(|did| **did == p));
+ let fn_call = parent.and_then(|p| {
+ lang_items::FN_TRAITS.iter().filter_map(|&l| tcx.lang_items().get(l)).find(|&id| id == p)
+ });
- let operator = (!from_hir_call)
- .then(|| parent)
- .flatten()
- .and_then(|p| tcx.lang_items().group(LangItemGroup::Op).iter().find(|did| **did == p));
+ let operator = if !from_hir_call && let Some(p) = parent {
+ lang_items::OPERATORS.iter().filter_map(|&l| tcx.lang_items().get(l)).find(|&id| id == p)
+ } else {
+ None
+ };
let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did);
// Check for a 'special' use of 'self' -
// an FnOnce call, an operator (e.g. `<<`), or a
// deref coercion.
- let kind = if let Some(&trait_id) = fn_call {
+ let kind = if let Some(trait_id) = fn_call {
Some(CallKind::FnCall { fn_trait_id: trait_id, self_ty: method_substs.type_at(0) })
- } else if let Some(&trait_id) = operator {
+ } else if let Some(trait_id) = operator {
Some(CallKind::Operator { self_arg, trait_id, self_ty: method_substs.type_at(0) })
} else if is_deref {
let deref_target = tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
pub mod collect_writes;
mod find_self_call;
mod might_permit_raw_init;
+mod type_name;
pub use self::aggregate::expand_aggregate;
pub use self::alignment::is_disaligned;
pub use self::call_kind::{call_kind, CallDesugaringKind, CallKind};
pub use self::find_self_call::find_self_call;
pub use self::might_permit_raw_init::might_permit_raw_init;
+pub use self::type_name::type_name;
--- /dev/null
+use rustc_data_structures::intern::Interned;
+use rustc_hir::def_id::CrateNum;
+use rustc_hir::definitions::DisambiguatedDefPathData;
+use rustc_middle::ty::{
+ self,
+ print::{PrettyPrinter, Print, Printer},
+ subst::{GenericArg, GenericArgKind},
+ Ty, TyCtxt,
+};
+use std::fmt::Write;
+
+struct AbsolutePathPrinter<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ path: String,
+}
+
+impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
+ type Error = std::fmt::Error;
+
+ type Path = Self;
+ type Region = Self;
+ type Type = Self;
+ type DynExistential = Self;
+ type Const = Self;
+
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn print_region(self, _region: ty::Region<'_>) -> Result<Self::Region, Self::Error> {
+ Ok(self)
+ }
+
+ fn print_type(mut self, ty: Ty<'tcx>) -> Result<Self::Type, Self::Error> {
+ match *ty.kind() {
+ // Types without identity.
+ ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Str
+ | ty::Array(_, _)
+ | ty::Slice(_)
+ | ty::RawPtr(_)
+ | ty::Ref(_, _, _)
+ | ty::FnPtr(_)
+ | ty::Never
+ | ty::Tuple(_)
+ | ty::Dynamic(_, _, _) => self.pretty_print_type(ty),
+
+ // Placeholders (all printed as `_` to uniformize them).
+ ty::Param(_) | ty::Bound(..) | ty::Placeholder(_) | ty::Infer(_) | ty::Error(_) => {
+ write!(self, "_")?;
+ Ok(self)
+ }
+
+ // Types with identity (print the module path).
+ ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), substs)
+ | ty::FnDef(def_id, substs)
+ | ty::Opaque(def_id, substs)
+ | ty::Projection(ty::ProjectionTy { item_def_id: def_id, substs })
+ | ty::Closure(def_id, substs)
+ | ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs),
+ ty::Foreign(def_id) => self.print_def_path(def_id, &[]),
+
+ ty::GeneratorWitness(_) => bug!("type_name: unexpected `GeneratorWitness`"),
+ }
+ }
+
+ fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
+ self.pretty_print_const(ct, false)
+ }
+
+ fn print_dyn_existential(
+ self,
+ predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>,
+ ) -> Result<Self::DynExistential, Self::Error> {
+ self.pretty_print_dyn_existential(predicates)
+ }
+
+ fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
+ self.path.push_str(self.tcx.crate_name(cnum).as_str());
+ Ok(self)
+ }
+
+ fn path_qualified(
+ self,
+ self_ty: Ty<'tcx>,
+ trait_ref: Option<ty::TraitRef<'tcx>>,
+ ) -> Result<Self::Path, Self::Error> {
+ self.pretty_path_qualified(self_ty, trait_ref)
+ }
+
+ fn path_append_impl(
+ self,
+ print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+ _disambiguated_data: &DisambiguatedDefPathData,
+ self_ty: Ty<'tcx>,
+ trait_ref: Option<ty::TraitRef<'tcx>>,
+ ) -> Result<Self::Path, Self::Error> {
+ self.pretty_path_append_impl(
+ |mut cx| {
+ cx = print_prefix(cx)?;
+
+ cx.path.push_str("::");
+
+ Ok(cx)
+ },
+ self_ty,
+ trait_ref,
+ )
+ }
+
+ fn path_append(
+ mut self,
+ print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+ disambiguated_data: &DisambiguatedDefPathData,
+ ) -> Result<Self::Path, Self::Error> {
+ self = print_prefix(self)?;
+
+ write!(self.path, "::{}", disambiguated_data.data).unwrap();
+
+ Ok(self)
+ }
+
+ fn path_generic_args(
+ mut self,
+ print_prefix: impl FnOnce(Self) -> Result<Self::Path, Self::Error>,
+ args: &[GenericArg<'tcx>],
+ ) -> Result<Self::Path, Self::Error> {
+ self = print_prefix(self)?;
+ let args =
+ args.iter().cloned().filter(|arg| !matches!(arg.unpack(), GenericArgKind::Lifetime(_)));
+ if args.clone().next().is_some() {
+ self.generic_delimiters(|cx| cx.comma_sep(args))
+ } else {
+ Ok(self)
+ }
+ }
+}
+
+impl<'tcx> PrettyPrinter<'tcx> for AbsolutePathPrinter<'tcx> {
+ fn should_print_region(&self, _region: ty::Region<'_>) -> bool {
+ false
+ }
+ fn comma_sep<T>(mut self, mut elems: impl Iterator<Item = T>) -> Result<Self, Self::Error>
+ where
+ T: Print<'tcx, Self, Output = Self, Error = Self::Error>,
+ {
+ if let Some(first) = elems.next() {
+ self = first.print(self)?;
+ for elem in elems {
+ self.path.push_str(", ");
+ self = elem.print(self)?;
+ }
+ }
+ Ok(self)
+ }
+
+ fn generic_delimiters(
+ mut self,
+ f: impl FnOnce(Self) -> Result<Self, Self::Error>,
+ ) -> Result<Self, Self::Error> {
+ write!(self, "<")?;
+
+ self = f(self)?;
+
+ write!(self, ">")?;
+
+ Ok(self)
+ }
+
+ fn should_print_verbose(&self) -> bool {
+ // `std::any::type_name` should never print verbose type names
+ false
+ }
+}
+
+impl Write for AbsolutePathPrinter<'_> {
+ fn write_str(&mut self, s: &str) -> std::fmt::Result {
+ self.path.push_str(s);
+ Ok(())
+ }
+}
+
+pub fn type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> String {
+ AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path
+}
rustc_serialize = { path = "../rustc_serialize" }
smallvec = { version = "1.8.1", features = ["const_generics", "union", "may_dangle"] }
stable_deref_trait = "1.0.0"
-stacker = "0.1.14"
+stacker = "0.1.15"
tempfile = "3.2"
-thin-vec = "0.2.8"
+thin-vec = "0.2.9"
tracing = "0.1"
[dependencies.parking_lot]
#![feature(new_uninit)]
#![feature(once_cell)]
#![feature(rustc_attrs)]
+#![feature(negative_impls)]
#![feature(test)]
#![feature(thread_id_value)]
#![feature(vec_into_raw_parts)]
pub mod tagged_ptr;
pub mod temp_dir;
pub mod unhash;
+pub mod unord;
pub use ena::undo_log;
pub use ena::unify;
#[cfg(parallel_compiler)]
#[inline(always)]
+ #[track_caller]
pub fn lock(&self) -> LockGuard<'_, T> {
if ERROR_CHECKING {
self.0.try_lock().expect("lock was already held")
#[cfg(not(parallel_compiler))]
#[inline(always)]
+ #[track_caller]
pub fn lock(&self) -> LockGuard<'_, T> {
self.0.borrow_mut()
}
#[inline(always)]
+ #[track_caller]
pub fn with_lock<F: FnOnce(&mut T) -> R, R>(&self, f: F) -> R {
f(&mut *self.lock())
}
#[inline(always)]
+ #[track_caller]
pub fn borrow(&self) -> LockGuard<'_, T> {
self.lock()
}
#[inline(always)]
+ #[track_caller]
pub fn borrow_mut(&self) -> LockGuard<'_, T> {
self.lock()
}
#[cfg(not(parallel_compiler))]
#[inline(always)]
+ #[track_caller]
pub fn read(&self) -> ReadGuard<'_, T> {
self.0.borrow()
}
}
#[inline(always)]
+ #[track_caller]
pub fn with_read_lock<F: FnOnce(&T) -> R, R>(&self, f: F) -> R {
f(&*self.read())
}
#[cfg(not(parallel_compiler))]
#[inline(always)]
+ #[track_caller]
pub fn write(&self) -> WriteGuard<'_, T> {
self.0.borrow_mut()
}
}
#[inline(always)]
+ #[track_caller]
pub fn with_write_lock<F: FnOnce(&mut T) -> R, R>(&self, f: F) -> R {
f(&mut *self.write())
}
#[inline(always)]
+ #[track_caller]
pub fn borrow(&self) -> ReadGuard<'_, T> {
self.read()
}
#[inline(always)]
+ #[track_caller]
pub fn borrow_mut(&self) -> WriteGuard<'_, T> {
self.write()
}
--- /dev/null
+//! This module contains collection types that don't expose their internal
+//! ordering. This is a useful property for deterministic computations, such
+//! as required by the query system.
+
+use rustc_hash::{FxHashMap, FxHashSet};
+use smallvec::SmallVec;
+use std::{
+ borrow::Borrow,
+ hash::Hash,
+ iter::{Product, Sum},
+};
+
+use crate::{
+ fingerprint::Fingerprint,
+ stable_hasher::{HashStable, StableHasher, ToStableHashKey},
+};
+
+/// `UnordItems` is the order-less version of `Iterator`. It only contains methods
+/// that don't (easily) expose an ordering of the underlying items.
+///
+/// Most methods take an `Fn` where the `Iterator`-version takes an `FnMut`. This
+/// is to reduce the risk of accidentally leaking the internal order via the closure
+/// environment. Otherwise one could easily do something like
+///
+/// ```rust,ignore (pseudo code)
+/// let mut ordered = vec![];
+/// unordered_items.all(|x| ordered.push(x));
+/// ```
+///
+/// It's still possible to do the same thing with an `Fn` by using interior mutability,
+/// but the chance of doing it accidentally is reduced.
+pub struct UnordItems<T, I: Iterator<Item = T>>(I);
+
+impl<T, I: Iterator<Item = T>> UnordItems<T, I> {
+ #[inline]
+ pub fn map<U, F: Fn(T) -> U>(self, f: F) -> UnordItems<U, impl Iterator<Item = U>> {
+ UnordItems(self.0.map(f))
+ }
+
+ #[inline]
+ pub fn all<U, F: Fn(T) -> bool>(mut self, f: F) -> bool {
+ self.0.all(f)
+ }
+
+ #[inline]
+ pub fn any<U, F: Fn(T) -> bool>(mut self, f: F) -> bool {
+ self.0.any(f)
+ }
+
+ #[inline]
+ pub fn filter<U, F: Fn(&T) -> bool>(self, f: F) -> UnordItems<T, impl Iterator<Item = T>> {
+ UnordItems(self.0.filter(f))
+ }
+
+ #[inline]
+ pub fn filter_map<U, F: Fn(T) -> Option<U>>(
+ self,
+ f: F,
+ ) -> UnordItems<U, impl Iterator<Item = U>> {
+ UnordItems(self.0.filter_map(f))
+ }
+
+ #[inline]
+ pub fn max(self) -> Option<T>
+ where
+ T: Ord,
+ {
+ self.0.max()
+ }
+
+ #[inline]
+ pub fn min(self) -> Option<T>
+ where
+ T: Ord,
+ {
+ self.0.min()
+ }
+
+ #[inline]
+ pub fn sum<S>(self) -> S
+ where
+ S: Sum<T>,
+ {
+ self.0.sum()
+ }
+
+ #[inline]
+ pub fn product<S>(self) -> S
+ where
+ S: Product<T>,
+ {
+ self.0.product()
+ }
+
+ #[inline]
+ pub fn count(self) -> usize {
+ self.0.count()
+ }
+}
+
+impl<'a, T: Clone + 'a, I: Iterator<Item = &'a T>> UnordItems<&'a T, I> {
+ #[inline]
+ pub fn cloned(self) -> UnordItems<T, impl Iterator<Item = T>> {
+ UnordItems(self.0.cloned())
+ }
+}
+
+impl<'a, T: Copy + 'a, I: Iterator<Item = &'a T>> UnordItems<&'a T, I> {
+ #[inline]
+ pub fn copied(self) -> UnordItems<T, impl Iterator<Item = T>> {
+ UnordItems(self.0.copied())
+ }
+}
+
+impl<T: Ord, I: Iterator<Item = T>> UnordItems<T, I> {
+ pub fn into_sorted<HCX>(self, hcx: &HCX) -> Vec<T>
+ where
+ T: ToStableHashKey<HCX>,
+ {
+ let mut items: Vec<T> = self.0.collect();
+ items.sort_by_cached_key(|x| x.to_stable_hash_key(hcx));
+ items
+ }
+
+ pub fn into_sorted_small_vec<HCX, const LEN: usize>(self, hcx: &HCX) -> SmallVec<[T; LEN]>
+ where
+ T: ToStableHashKey<HCX>,
+ {
+ let mut items: SmallVec<[T; LEN]> = self.0.collect();
+ items.sort_by_cached_key(|x| x.to_stable_hash_key(hcx));
+ items
+ }
+}
+
+/// This is a set collection type that tries very hard to not expose
+/// any internal iteration. This is a useful property when trying to
+/// uphold the determinism invariants imposed by the query system.
+///
+/// This collection type is a good choice for set-like collections the
+/// keys of which don't have a semantic ordering.
+///
+/// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533)
+/// for more information.
+#[derive(Debug, Eq, PartialEq, Clone, Encodable, Decodable)]
+pub struct UnordSet<V: Eq + Hash> {
+ inner: FxHashSet<V>,
+}
+
+impl<V: Eq + Hash> Default for UnordSet<V> {
+ fn default() -> Self {
+ Self { inner: FxHashSet::default() }
+ }
+}
+
+impl<V: Eq + Hash> UnordSet<V> {
+ #[inline]
+ pub fn new() -> Self {
+ Self { inner: Default::default() }
+ }
+
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.inner.len()
+ }
+
+ #[inline]
+ pub fn insert(&mut self, v: V) -> bool {
+ self.inner.insert(v)
+ }
+
+ #[inline]
+ pub fn contains<Q: ?Sized>(&self, v: &Q) -> bool
+ where
+ V: Borrow<Q>,
+ Q: Hash + Eq,
+ {
+ self.inner.contains(v)
+ }
+
+ #[inline]
+ pub fn items<'a>(&'a self) -> UnordItems<&'a V, impl Iterator<Item = &'a V>> {
+ UnordItems(self.inner.iter())
+ }
+
+ #[inline]
+ pub fn into_items(self) -> UnordItems<V, impl Iterator<Item = V>> {
+ UnordItems(self.inner.into_iter())
+ }
+
+ // We can safely extend this UnordSet from a set of unordered values because that
+ // won't expose the internal ordering anywhere.
+ #[inline]
+ pub fn extend<I: Iterator<Item = V>>(&mut self, items: UnordItems<V, I>) {
+ self.inner.extend(items.0)
+ }
+}
+
+impl<V: Hash + Eq> Extend<V> for UnordSet<V> {
+ fn extend<T: IntoIterator<Item = V>>(&mut self, iter: T) {
+ self.inner.extend(iter)
+ }
+}
+
+impl<HCX, V: Hash + Eq + HashStable<HCX>> HashStable<HCX> for UnordSet<V> {
+ #[inline]
+ fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
+ hash_iter_order_independent(self.inner.iter(), hcx, hasher);
+ }
+}
+
+/// This is a map collection type that tries very hard to not expose
+/// any internal iteration. This is a useful property when trying to
+/// uphold the determinism invariants imposed by the query system.
+///
+/// This collection type is a good choice for map-like collections the
+/// keys of which don't have a semantic ordering.
+///
+/// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533)
+/// for more information.
+#[derive(Debug, Eq, PartialEq, Clone, Encodable, Decodable)]
+pub struct UnordMap<K: Eq + Hash, V> {
+ inner: FxHashMap<K, V>,
+}
+
+impl<K: Eq + Hash, V> Default for UnordMap<K, V> {
+ fn default() -> Self {
+ Self { inner: FxHashMap::default() }
+ }
+}
+
+impl<K: Hash + Eq, V> Extend<(K, V)> for UnordMap<K, V> {
+ fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
+ self.inner.extend(iter)
+ }
+}
+
+impl<K: Eq + Hash, V> UnordMap<K, V> {
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.inner.len()
+ }
+
+ #[inline]
+ pub fn insert(&mut self, k: K, v: V) -> Option<V> {
+ self.inner.insert(k, v)
+ }
+
+ #[inline]
+ pub fn contains_key<Q: ?Sized>(&self, k: &Q) -> bool
+ where
+ K: Borrow<Q>,
+ Q: Hash + Eq,
+ {
+ self.inner.contains_key(k)
+ }
+
+ #[inline]
+ pub fn items<'a>(&'a self) -> UnordItems<(&'a K, &'a V), impl Iterator<Item = (&'a K, &'a V)>> {
+ UnordItems(self.inner.iter())
+ }
+
+ #[inline]
+ pub fn into_items(self) -> UnordItems<(K, V), impl Iterator<Item = (K, V)>> {
+ UnordItems(self.inner.into_iter())
+ }
+
+ // We can safely extend this UnordMap from a set of unordered values because that
+ // won't expose the internal ordering anywhere.
+ #[inline]
+ pub fn extend<I: Iterator<Item = (K, V)>>(&mut self, items: UnordItems<(K, V), I>) {
+ self.inner.extend(items.0)
+ }
+}
+
+impl<HCX, K: Hash + Eq + HashStable<HCX>, V: HashStable<HCX>> HashStable<HCX> for UnordMap<K, V> {
+ #[inline]
+ fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
+ hash_iter_order_independent(self.inner.iter(), hcx, hasher);
+ }
+}
+
+/// This is a collection type that tries very hard to not expose
+/// any internal iteration. This is a useful property when trying to
+/// uphold the determinism invariants imposed by the query system.
+///
+/// This collection type is a good choice for collections the
+/// keys of which don't have a semantic ordering and don't implement
+/// `Hash` or `Eq`.
+///
+/// See [MCP 533](https://github.com/rust-lang/compiler-team/issues/533)
+/// for more information.
+#[derive(Default, Debug, Eq, PartialEq, Clone, Encodable, Decodable)]
+pub struct UnordBag<V> {
+ inner: Vec<V>,
+}
+
+impl<V> UnordBag<V> {
+ #[inline]
+ pub fn new() -> Self {
+ Self { inner: Default::default() }
+ }
+
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.inner.len()
+ }
+
+ #[inline]
+ pub fn push(&mut self, v: V) {
+ self.inner.push(v);
+ }
+
+ #[inline]
+ pub fn items<'a>(&'a self) -> UnordItems<&'a V, impl Iterator<Item = &'a V>> {
+ UnordItems(self.inner.iter())
+ }
+
+ #[inline]
+ pub fn into_items(self) -> UnordItems<V, impl Iterator<Item = V>> {
+ UnordItems(self.inner.into_iter())
+ }
+
+ // We can safely extend this UnordSet from a set of unordered values because that
+ // won't expose the internal ordering anywhere.
+ #[inline]
+ pub fn extend<I: Iterator<Item = V>>(&mut self, items: UnordItems<V, I>) {
+ self.inner.extend(items.0)
+ }
+}
+
+impl<T> Extend<T> for UnordBag<T> {
+ fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
+ self.inner.extend(iter)
+ }
+}
+
+impl<HCX, V: Hash + Eq + HashStable<HCX>> HashStable<HCX> for UnordBag<V> {
+ #[inline]
+ fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
+ hash_iter_order_independent(self.inner.iter(), hcx, hasher);
+ }
+}
+
+fn hash_iter_order_independent<
+ HCX,
+ T: HashStable<HCX>,
+ I: Iterator<Item = T> + ExactSizeIterator,
+>(
+ mut it: I,
+ hcx: &mut HCX,
+ hasher: &mut StableHasher,
+) {
+ let len = it.len();
+ len.hash_stable(hcx, hasher);
+
+ match len {
+ 0 => {
+ // We're done
+ }
+ 1 => {
+ // No need to instantiate a hasher
+ it.next().unwrap().hash_stable(hcx, hasher);
+ }
+ _ => {
+ let mut accumulator = Fingerprint::ZERO;
+ for item in it {
+ let mut item_hasher = StableHasher::new();
+ item.hash_stable(hcx, &mut item_hasher);
+ let item_fingerprint: Fingerprint = item_hasher.finish();
+ accumulator = accumulator.combine_commutative(item_fingerprint);
+ }
+ accumulator.hash_stable(hcx, hasher);
+ }
+ }
+}
+
+// Do not implement IntoIterator for the collections in this module.
+// They only exist to hide iteration order in the first place.
+impl<T> !IntoIterator for UnordBag<T> {}
+impl<V> !IntoIterator for UnordSet<V> {}
+impl<K, V> !IntoIterator for UnordMap<K, V> {}
+impl<T, I> !IntoIterator for UnordItems<T, I> {}
// Any output here interferes with Cargo's parsing of other printed output
NativeStaticLibs => {}
LinkArgs => {}
+ SplitDebuginfo => {
+ use rustc_target::spec::SplitDebuginfo::{Off, Packed, Unpacked};
+
+ for split in &[Off, Packed, Unpacked] {
+ let stable = sess.target.options.supported_split_debuginfo.contains(split);
+ let unstable_ok = sess.unstable_options();
+ if stable || unstable_ok {
+ println!("{}", split);
+ }
+ }
+ }
}
}
Compilation::Stop
false,
None,
false,
+ false,
));
let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
-A type parameter that is specified for `impl` is not constrained.
+A type, const or lifetime parameter that is specified for `impl` is not
+constrained.
Erroneous code example:
}
```
-Any type parameter of an `impl` must meet at least one of
-the following criteria:
+Any type or const parameter of an `impl` must meet at least one of the
+following criteria:
- it appears in the _implementing type_ of the impl, e.g. `impl<T> Foo<T>`
- for a trait impl, it appears in the _implemented trait_, e.g.
- it is bound as an associated type, e.g. `impl<T, U> SomeTrait for T
where T: AnotherTrait<AssocType=U>`
+Any unconstrained lifetime parameter of an `impl` is not supported if the
+lifetime parameter is used by an associated type.
+
### Error example 1
Suppose we have a struct `Foo` and we would like to define some methods for it.
(`Foo`) of the impl. In this case, we can fix the error by moving the type
parameter from the `impl` to the method `get`:
-
```
struct Foo;
}
```
+### Error example 3
+
+Suppose we have a struct `Foo` and we would like to define some methods for it.
+The following code example has a definition which leads to a compiler error:
+
+```compile_fail,E0207
+struct Foo;
+
+impl<const T: i32> Foo {
+ // error: the const parameter `T` is not constrained by the impl trait, self
+ // type, or predicates [E0207]
+ fn get(&self) -> i32 {
+ i32::default()
+ }
+}
+```
+
+The problem is that the const parameter `T` does not appear in the implementing
+type (`Foo`) of the impl. In this case, we can fix the error by moving the type
+parameter from the `impl` to the method `get`:
+
+
+```
+struct Foo;
+
+// Move the const parameter from the impl to the method
+impl Foo {
+ fn get<const T: i32>(&self) -> i32 {
+ i32::default()
+ }
+}
+```
+
+### Error example 4
+
+Suppose we have a struct `Foo` and a struct `Bar` that uses lifetime `'a`. We
+would like to implement trait `Contains` for `Foo`. The trait `Contains` have
+the associated type `B`. The following code example has a definition which
+leads to a compiler error:
+
+```compile_fail,E0207
+struct Foo;
+struct Bar<'a>;
+
+trait Contains {
+ type B;
+
+ fn get(&self) -> i32;
+}
+
+impl<'a> Contains for Foo {
+ type B = Bar<'a>;
+
+ // error: the lifetime parameter `'a` is not constrained by the impl trait,
+ // self type, or predicates [E0207]
+ fn get(&self) -> i32 {
+ i32::default()
+ }
+}
+```
+
+Please note that unconstrained lifetime parameters are not supported if they are
+being used by an associated type.
+
### Additional information
For more information, please see [RFC 447].
Some types have no ownership semantics at all and are trivial to duplicate. An
example is `i32` and the other number types. We don't have to call `.clone()` to
-clone them, because they are marked `Copy` in addition to `Clone`. Implicit
+clone them, because they are marked `Copy` in addition to `Clone`. Implicit
cloning is more convenient in this case. We can mark our own types `Copy` if
all their members also are marked `Copy`.
borrowck_used_impl_require_static =
the used `impl` has a `'static` requirement
+
+borrowck_capture_kind_label =
+ capture is {$kind_desc} because of use here
+
+borrowck_var_borrow_by_use_place_in_generator =
+ borrow occurs due to use of {$place} in closure in generator
+
+borrowck_var_borrow_by_use_place_in_closure =
+ borrow occurs due to use of {$place} in closure
+
+borrowck_var_borrow_by_use_place =
+ borrow occurs due to use of {$place}
codegen_ssa_thorin_object_write = {$error}
codegen_ssa_thorin_gimli_read = {$error}
codegen_ssa_thorin_gimli_write = {$error}
+
+codegen_ssa_link_exe_unexpected_error = `link.exe` returned an unexpected error
+
+codegen_ssa_repair_vs_build_tools = the Visual Studio build tools may need to be repaired using the Visual Studio installer
+
+codegen_ssa_missing_cpp_build_tool_component = or a necessary component may be missing from the "C++ build tools" workload
+
+codegen_ssa_select_cpp_build_tool_workload = in the Visual Studio installer, ensure the "C++ build tools" workload is selected
+
+codegen_ssa_visual_studio_not_installed = you may need to install Visual Studio build tools with the "C++ build tools" workload
+
+codegen_ssa_linker_not_found = linker `{$linker_path}` not found
+ .note = {$error}
+
+codegen_ssa_unable_to_exe_linker = could not exec the linker `{$linker_path}`
+ .note = {$error}
+ .command_note = {$command_formatted}
+
+codegen_ssa_msvc_missing_linker = the msvc targets depend on the msvc linker but `link.exe` was not found
+
+codegen_ssa_check_installed_visual_studio = please ensure that Visual Studio 2017 or later, or Build Tools for Visual Studio were installed with the Visual C++ option.
+
+codegen_ssa_unsufficient_vs_code_product = VS Code is a different product, and is not sufficient.
+
+codegen_ssa_processing_dymutil_failed = processing debug info with `dsymutil` failed: {$status}
+ .note = {$output}
+
+codegen_ssa_unable_to_run_dsymutil = unable to run `dsymutil`: {$error}
+
+codegen_ssa_stripping_debu_info_failed = stripping debug info with `{$util}` failed: {$status}
+ .note = {$output}
+
+codegen_ssa_unable_to_run = unable to run `{$util}`: {$error}
+
+codegen_ssa_linker_file_stem = couldn't extract file stem from specified linker
+
+codegen_ssa_static_library_native_artifacts = Link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms.
+
+codegen_ssa_native_static_libs = native-static-libs: {$arguments}
+
+codegen_ssa_link_script_unavailable = can only use link script when linking with GNU-like linker
+
+codegen_ssa_link_script_write_failure = failed to write link script to {$path}: {$error}
+
+codegen_ssa_failed_to_write = failed to write {$path}: {$error}
+
+codegen_ssa_unable_to_write_debugger_visualizer = Unable to write debugger visualizer file `{$path}`: {$error}
+
+codegen_ssa_rlib_archive_build_failure = failed to build archive from rlib: {$error}
+
+codegen_ssa_option_gcc_only = option `-Z gcc-ld` is used even though linker flavor is not gcc
+
+codegen_ssa_extract_bundled_libs_open_file = failed to open file '{$rlib}': {$error}
+codegen_ssa_extract_bundled_libs_mmap_file = failed to mmap file '{$rlib}': {$error}
+codegen_ssa_extract_bundled_libs_parse_archive = failed to parse archive '{$rlib}': {$error}
+codegen_ssa_extract_bundled_libs_read_entry = failed to read entry '{$rlib}': {$error}
+codegen_ssa_extract_bundled_libs_archive_member = failed to get data from archive member '{$rlib}': {$error}
+codegen_ssa_extract_bundled_libs_convert_name = failed to convert name '{$rlib}': {$error}
+codegen_ssa_extract_bundled_libs_write_file = failed to write file '{$rlib}': {$error}
+
+codegen_ssa_unsupported_arch = unsupported arch `{$arch}` for os `{$os}`
+
+codegen_ssa_apple_sdk_error_sdk_path = failed to get {$sdk_name} SDK path: {error}
hir_analysis_expected_return_type = expected `{$expected}` because of return type
hir_analysis_unconstrained_opaque_type = unconstrained opaque type
- .note = `{$name}` must be used in combination with a concrete type within the same module
+ .note = `{$name}` must be used in combination with a concrete type within the same {$what}
hir_analysis_missing_type_params =
the type {$parameterCount ->
hir_analysis_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}`
hir_analysis_add_missing_parentheses_in_range = you must surround the range in parentheses to call its `{$func_name}` function
+
+hir_analysis_const_impl_for_non_const_trait =
+ const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]`
+ .suggestion = mark `{$trait_name}` as const
+ .note = marking a trait with `#[const_trait]` ensures all default method bodies are `const`
+ .adding = adding a non-const method body in the future would be a breaking change
+
+hir_analysis_const_bound_for_non_const_trait =
+ ~const can only be applied to `#[const_trait]` traits
+
+hir_analysis_self_in_impl_self =
+ `Self` is not valid in the self type of an impl block
+ .note = replace `Self` with a different type
metadata_prev_global_alloc =
previous global allocator defined here
+metadata_no_multiple_alloc_error_handler =
+ cannot define multiple allocation error handlers
+ .label = cannot define a new allocation error handler
+
+metadata_prev_alloc_error_handler =
+ previous allocation error handler defined here
+
metadata_conflicting_global_alloc =
the `#[global_allocator]` in {$other_crate_name} conflicts with global allocator in: {$crate_name}
+metadata_conflicting_alloc_error_handler =
+ the `#[alloc_error_handler]` in {$other_crate_name} conflicts with allocation error handler in: {$crate_name}
+
metadata_global_alloc_required =
no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait
+metadata_alloc_func_required =
+ `#[alloc_error_handler]` function required, but not found
+
+metadata_missing_alloc_error_handler =
+ use `#![feature(default_alloc_error_handler)]` for a default error handler
+
metadata_no_transitive_needs_dep =
the crate `{$crate_name}` cannot depend on a crate that needs {$needs_crate_name}, but it depends on `{$deps_crate_name}`
middle_cannot_be_normalized =
unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized
+
+middle_strict_coherence_needs_negative_coherence =
+ to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled
+ .label = due to this attribute
moving {$size} bytes
.label = value moved from here
.note = The current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
-
-monomorphize_requires_lang_item =
- requires `{$lang_item}` lang_item
parser_invalid_block_macro_segment = cannot use a `block` macro fragment here
.label = the `block` fragment is within this context
+parser_expect_dotdot_not_dotdotdot = expected `..`, found `...`
+ .suggestion = use `..` to fill in the rest of the fields
+
parser_if_expression_missing_then_block = this `if` expression is missing a block after the condition
.add_then_block = add a block here
.condition_possibly_unfinished = this binary operation is possibly unfinished
passes_missing_panic_handler =
`#[panic_handler]` function required, but not found
-passes_alloc_func_required =
- `#[alloc_error_handler]` function required, but not found
-
-passes_missing_alloc_error_handler =
- use `#![feature(default_alloc_error_handler)]` for a default error handler
-
passes_missing_lang_item =
language item required, but not found: `{$name}`
.note = this can occur when a binary crate with `#![no_std]` is compiled for a target where `{$name}` is defined in the standard library
.async_block_label = enclosing `async` block
passes_outside_loop =
- `{$name}` outside of a loop
- .label = cannot `{$name}` outside of a loop
+ `{$name}` outside of a loop{$is_break ->
+ [true] {" or labeled block"}
+ *[false] {""}
+ }
+ .label = cannot `{$name}` outside of a loop{$is_break ->
+ [true] {" or labeled block"}
+ *[false] {""}
+ }
passes_unlabeled_in_labeled_block =
unlabeled `{$cf_type}` inside of a labeled block
attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
.help = make the function or method const
.label = attribute specified here
+
+passes_dead_codes =
+ { $multiple ->
+ *[true] multiple {$descr}s are
+ [false] { $num ->
+ [one] {$descr} {$name_list} is
+ *[other] {$descr}s {$name_list} are
+ }
+ } never {$participle}
+
+passes_change_fields_to_be_of_unit_type =
+ consider changing the { $num ->
+ [one] field
+ *[other] fields
+ } to be of unit type to suppress this warning while preserving the field numbering, or remove the { $num ->
+ [one] field
+ *[other] fields
+ }
+
+passes_parent_info =
+ {$num ->
+ [one] {$descr}
+ *[other] {$descr}s
+ } in this {$parent_descr}
+
+passes_ignored_derived_impls =
+ `{$name}` has {$trait_list_len ->
+ [one] a derived impl
+ *[other] derived impls
+ } for the {$trait_list_len ->
+ [one] trait {$trait_list}, but this is
+ *[other] traits {$trait_list}, but these are
+ } intentionally ignored during dead code analysis
use std::borrow::Cow;
use std::fmt;
use std::hash::{Hash, Hasher};
+use std::panic::Location;
/// Error type for `Diagnostic`'s `suggestions` field, indicating that
/// `.disable_suggestions()` was called on the `Diagnostic`.
/// If diagnostic is from Lint, custom hash function ignores notes
/// otherwise hash is based on the all the fields
pub is_lint: bool,
+
+ /// With `-Ztrack_diagnostics` enabled,
+ /// we print where in rustc this error was emitted.
+ pub emitted_at: DiagnosticLocation,
+}
+
+#[derive(Clone, Debug, Encodable, Decodable)]
+pub struct DiagnosticLocation {
+ file: Cow<'static, str>,
+ line: u32,
+ col: u32,
+}
+
+impl DiagnosticLocation {
+ #[track_caller]
+ fn caller() -> Self {
+ let loc = Location::caller();
+ DiagnosticLocation { file: loc.file().into(), line: loc.line(), col: loc.column() }
+ }
+}
+
+impl fmt::Display for DiagnosticLocation {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}:{}:{}", self.file, self.line, self.col)
+ }
}
#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
}
impl Diagnostic {
+ #[track_caller]
pub fn new<M: Into<DiagnosticMessage>>(level: Level, message: M) -> Self {
Diagnostic::new_with_code(level, None, message)
}
+ #[track_caller]
pub fn new_with_code<M: Into<DiagnosticMessage>>(
level: Level,
code: Option<DiagnosticId>,
args: Default::default(),
sort_span: DUMMY_SP,
is_lint: false,
+ emitted_at: DiagnosticLocation::caller(),
}
}
impl<'a> DiagnosticBuilder<'a, ErrorGuaranteed> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].
+ #[track_caller]
pub(crate) fn new_guaranteeing_error<M: Into<DiagnosticMessage>, const L: Level>(
handler: &'a Handler,
message: M,
}
}
+ #[track_caller]
fn make_diagnostic_builder(
handler: &Handler,
msg: impl Into<DiagnosticMessage>,
impl<'a> DiagnosticBuilder<'a, ()> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].
+ #[track_caller]
pub(crate) fn new<M: Into<DiagnosticMessage>>(
handler: &'a Handler,
level: Level,
/// Creates a new `DiagnosticBuilder` with an already constructed
/// diagnostic.
+ #[track_caller]
pub(crate) fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
debug!("Created new diagnostic");
Self {
impl<'a> DiagnosticBuilder<'a, !> {
/// Convenience function for internal use, clients should use one of the
/// `struct_*` methods on [`Handler`].
+ #[track_caller]
pub(crate) fn new_fatal(handler: &'a Handler, message: impl Into<DiagnosticMessage>) -> Self {
let diagnostic = Diagnostic::new_with_code(Level::Fatal, None, message);
Self::new_diagnostic_fatal(handler, diagnostic)
/// In the meantime, though, callsites are required to deal with the "bug"
/// locally in whichever way makes the most sense.
#[track_caller]
- pub fn delay_as_bug(&mut self) {
+ pub fn delay_as_bug(&mut self) -> G {
self.downgrade_to_delayed_bug();
- self.emit();
+ self.emit()
}
forward!(
use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple};
use std::borrow::Cow;
use std::fmt;
+use std::fmt::Write;
use std::num::ParseIntError;
use std::path::{Path, PathBuf};
+use std::process::ExitStatus;
pub struct DiagnosticArgFromDisplay<'a>(pub &'a dyn fmt::Display);
i128,
u128,
std::io::Error,
+ std::boxed::Box<dyn std::error::Error>,
std::num::NonZeroU32,
hir::Target,
Edition,
ParseIntError,
StackProtector,
&TargetTriple,
- SplitDebuginfo
+ SplitDebuginfo,
+ ExitStatus,
);
impl IntoDiagnosticArg for bool {
}
}
+#[derive(Clone)]
+pub struct DiagnosticSymbolList(Vec<Symbol>);
+
+impl From<Vec<Symbol>> for DiagnosticSymbolList {
+ fn from(v: Vec<Symbol>) -> Self {
+ DiagnosticSymbolList(v)
+ }
+}
+
+impl IntoDiagnosticArg for DiagnosticSymbolList {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ // FIXME: replace the logic here with a real list formatter
+ let symbols = match &self.0[..] {
+ [symbol] => format!("`{symbol}`"),
+ [symbol, last] => {
+ format!("`{symbol}` and `{last}`",)
+ }
+ [symbols @ .., last] => {
+ let mut result = String::new();
+ for symbol in symbols {
+ write!(result, "`{symbol}`, ").unwrap();
+ }
+ write!(result, "and `{last}`").unwrap();
+ result
+ }
+ [] => unreachable!(),
+ };
+ DiagnosticArgValue::Str(Cow::Owned(symbols))
+ }
+}
+
impl IntoDiagnostic<'_, !> for TargetDataLayoutErrors<'_> {
fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> {
let mut diag;
use crate::styled_buffer::StyledBuffer;
use crate::translation::{to_fluent_args, Translate};
use crate::{
- CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, FluentBundle, Handler,
- LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, SubstitutionHighlight, SuggestionStyle,
+ diagnostic::DiagnosticLocation, CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage,
+ FluentBundle, Handler, LazyFallbackBundle, Level, MultiSpan, SubDiagnostic,
+ SubstitutionHighlight, SuggestionStyle,
};
-
use rustc_lint_defs::pluralize;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
teach: bool,
diagnostic_width: Option<usize>,
macro_backtrace: bool,
+ track_diagnostics: bool,
) -> EmitterWriter {
let (short, color_config) = self.unzip();
let color = color_config.suggests_using_colors();
color,
diagnostic_width,
macro_backtrace,
+ track_diagnostics,
)
}
}
&primary_span,
&children,
&suggestions,
+ self.track_diagnostics.then_some(&diag.emitted_at),
);
}
diagnostic_width: Option<usize>,
macro_backtrace: bool,
+ track_diagnostics: bool,
}
#[derive(Debug)]
teach: bool,
diagnostic_width: Option<usize>,
macro_backtrace: bool,
+ track_diagnostics: bool,
) -> EmitterWriter {
let dst = Destination::from_stderr(color_config);
EmitterWriter {
ui_testing: false,
diagnostic_width,
macro_backtrace,
+ track_diagnostics,
}
}
colored: bool,
diagnostic_width: Option<usize>,
macro_backtrace: bool,
+ track_diagnostics: bool,
) -> EmitterWriter {
EmitterWriter {
dst: Raw(dst, colored),
ui_testing: false,
diagnostic_width,
macro_backtrace,
+ track_diagnostics,
}
}
level: &Level,
max_line_num_len: usize,
is_secondary: bool,
+ emitted_at: Option<&DiagnosticLocation>,
) -> io::Result<()> {
let mut buffer = StyledBuffer::new();
}
}
}
-
let mut annotated_files = FileWithAnnotatedLines::collect_annotations(self, args, msp);
// Make sure our primary file comes first
}
}
+ if let Some(tracked) = emitted_at {
+ let track = format!("-Ztrack-diagnostics: created at {tracked}");
+ let len = buffer.num_lines();
+ buffer.append(len, &track, Style::NoStyle);
+ }
+
// final step: take our styled buffer, render it, then output it
emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?;
span: &MultiSpan,
children: &[SubDiagnostic],
suggestions: &[CodeSuggestion],
+ emitted_at: Option<&DiagnosticLocation>,
) {
let max_line_num_len = if self.ui_testing {
ANONYMIZED_LINE_NUM.len()
num_decimal_digits(n)
};
- match self.emit_message_default(span, message, args, code, level, max_line_num_len, false) {
+ match self.emit_message_default(
+ span,
+ message,
+ args,
+ code,
+ level,
+ max_line_num_len,
+ false,
+ emitted_at,
+ ) {
Ok(()) => {
if !children.is_empty()
|| suggestions.iter().any(|s| s.style != SuggestionStyle::CompletelyHidden)
&child.level,
max_line_num_len,
true,
+ None,
) {
panic!("failed to emit error: {}", err);
}
&Level::Help,
max_line_num_len,
true,
+ None,
) {
panic!("failed to emit error: {}", e);
}
json_rendered: HumanReadableErrorType,
diagnostic_width: Option<usize>,
macro_backtrace: bool,
+ track_diagnostics: bool,
}
impl JsonEmitter {
json_rendered: HumanReadableErrorType,
diagnostic_width: Option<usize>,
macro_backtrace: bool,
+ track_diagnostics: bool,
) -> JsonEmitter {
JsonEmitter {
dst: Box::new(io::BufWriter::new(io::stderr())),
json_rendered,
diagnostic_width,
macro_backtrace,
+ track_diagnostics,
}
}
fallback_bundle: LazyFallbackBundle,
diagnostic_width: Option<usize>,
macro_backtrace: bool,
+ track_diagnostics: bool,
) -> JsonEmitter {
let file_path_mapping = FilePathMapping::empty();
JsonEmitter::stderr(
json_rendered,
diagnostic_width,
macro_backtrace,
+ track_diagnostics,
)
}
json_rendered: HumanReadableErrorType,
diagnostic_width: Option<usize>,
macro_backtrace: bool,
+ track_diagnostics: bool,
) -> JsonEmitter {
JsonEmitter {
dst,
json_rendered,
diagnostic_width,
macro_backtrace,
+ track_diagnostics,
}
}
false,
je.diagnostic_width,
je.macro_backtrace,
+ je.track_diagnostics,
)
.ui_testing(je.ui_testing)
.emit_diagnostic(diag);
HumanReadableErrorType::Short(ColorConfig::Never),
None,
false,
+ false,
);
let span = Span::with_root_ctxt(BytePos(span.0), BytePos(span.1));
DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
};
pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, Noted};
-pub use diagnostic_impls::DiagnosticArgFromDisplay;
+pub use diagnostic_impls::{DiagnosticArgFromDisplay, DiagnosticSymbolList};
use std::backtrace::Backtrace;
/// A handler deals with errors and other compiler output.
pub macro_backtrace: bool,
/// If true, identical diagnostics are reported only once.
pub deduplicate_diagnostics: bool,
+ /// Track where errors are created. Enabled with `-Ztrack-diagnostics`.
+ pub track_diagnostics: bool,
}
impl Drop for HandlerInner {
false,
None,
flags.macro_backtrace,
+ flags.track_diagnostics,
));
Self::with_emitter_and_flags(emitter, flags)
}
/// Construct a builder with the `msg` at the level appropriate for the specific `EmissionGuarantee`.
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_diagnostic<G: EmissionGuarantee>(
&self,
msg: impl Into<DiagnosticMessage>,
/// * `can_emit_warnings` is `true`
/// * `is_force_warn` was set in `DiagnosticId::Lint`
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_span_warn(
&self,
span: impl Into<MultiSpan>,
/// Attempting to `.emit()` the builder will only emit if either:
/// * `can_emit_warnings` is `true`
/// * `is_force_warn` was set in `DiagnosticId::Lint`
+ #[track_caller]
pub fn struct_span_warn_with_expectation(
&self,
span: impl Into<MultiSpan>,
/// Construct a builder at the `Allow` level at the given `span` and with the `msg`.
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_span_allow(
&self,
span: impl Into<MultiSpan>,
/// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
/// Also include a code.
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_span_warn_with_code(
&self,
span: impl Into<MultiSpan>,
/// * `can_emit_warnings` is `true`
/// * `is_force_warn` was set in `DiagnosticId::Lint`
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
DiagnosticBuilder::new(self, Level::Warning(None), msg)
}
/// Attempting to `.emit()` the builder will only emit if either:
/// * `can_emit_warnings` is `true`
/// * `is_force_warn` was set in `DiagnosticId::Lint`
+ #[track_caller]
pub fn struct_warn_with_expectation(
&self,
msg: impl Into<DiagnosticMessage>,
/// Construct a builder at the `Allow` level with the `msg`.
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
DiagnosticBuilder::new(self, Level::Allow, msg)
}
/// Construct a builder at the `Expect` level with the `msg`.
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_expect(
&self,
msg: impl Into<DiagnosticMessage>,
/// Construct a builder at the `Error` level at the given `span` and with the `msg`.
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_span_err(
&self,
span: impl Into<MultiSpan>,
/// Construct a builder at the `Error` level at the given `span`, with the `msg`, and `code`.
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_span_err_with_code(
&self,
span: impl Into<MultiSpan>,
/// Construct a builder at the `Error` level with the `msg`.
// FIXME: This method should be removed (every error should have an associated error code).
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_err(
&self,
msg: impl Into<DiagnosticMessage>,
/// This should only be used by `rustc_middle::lint::struct_lint_level`. Do not use it for hard errors.
#[doc(hidden)]
+ #[track_caller]
pub fn struct_err_lint(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
DiagnosticBuilder::new(self, Level::Error { lint: true }, msg)
}
/// Construct a builder at the `Error` level with the `msg` and the `code`.
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_err_with_code(
&self,
msg: impl Into<DiagnosticMessage>,
/// Construct a builder at the `Warn` level with the `msg` and the `code`.
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_warn_with_code(
&self,
msg: impl Into<DiagnosticMessage>,
/// Construct a builder at the `Fatal` level at the given `span` and with the `msg`.
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_span_fatal(
&self,
span: impl Into<MultiSpan>,
/// Construct a builder at the `Fatal` level at the given `span`, with the `msg`, and `code`.
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_span_fatal_with_code(
&self,
span: impl Into<MultiSpan>,
/// Construct a builder at the `Error` level with the `msg`.
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
DiagnosticBuilder::new_fatal(self, msg)
}
/// Construct a builder at the `Note` level with the `msg`.
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_note_without_error(
&self,
msg: impl Into<DiagnosticMessage>,
}
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn span_fatal(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
self.emit_diag_at_span(Diagnostic::new(Fatal, msg), span);
FatalError.raise()
}
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn span_fatal_with_code(
&self,
span: impl Into<MultiSpan>,
}
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn span_err(
&self,
span: impl Into<MultiSpan>,
}
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn span_err_with_code(
&self,
span: impl Into<MultiSpan>,
}
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
self.emit_diag_at_span(Diagnostic::new(Warning(None), msg), span);
}
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn span_warn_with_code(
&self,
span: impl Into<MultiSpan>,
self.inner.borrow_mut().delay_good_path_bug(msg)
}
+ #[track_caller]
pub fn span_bug_no_panic(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
self.emit_diag_at_span(Diagnostic::new(Bug, msg), span);
}
+ #[track_caller]
pub fn span_note_without_error(
&self,
span: impl Into<MultiSpan>,
self.emit_diag_at_span(Diagnostic::new(Note, msg), span);
}
+ #[track_caller]
pub fn span_note_diag(
&self,
span: Span,
}
}
+ #[track_caller]
fn span_bug(&mut self, sp: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
self.emit_diag_at_span(Diagnostic::new(Bug, msg), sp);
panic::panic_any(ExplicitBug);
// hacky, but speeds up the `html5ever` benchmark significantly. (Issue
// 68836 suggests a more comprehensive but more complex change to deal with
// this situation.)
+ // FIXME(Nilstrieb): Stop recovery from happening on this parser and retry later with recovery if the macro failed to match.
let parser = parser_from_cx(sess, arg.clone());
// Try each arm's matchers.
false,
None,
false,
+ false,
);
let handler = Handler::with_emitter(true, None, Box::new(emitter));
handler.span_err(msp, "foo");
(accepted, infer_outlives_requirements, "1.30.0", Some(44493), None),
/// Allows irrefutable patterns in `if let` and `while let` statements (RFC 2086).
(accepted, irrefutable_let_patterns, "1.33.0", Some(44495), None),
+ /// Allows `#[instruction_set(_)]` attribute.
+ (accepted, isa_attribute, "CURRENT_RUSTC_VERSION", Some(74727), None),
/// Allows some increased flexibility in the name resolution rules,
/// especially around globs and shadowing (RFC 1560).
(accepted, item_like_imports, "1.15.0", Some(35120), None),
(active, exclusive_range_pattern, "1.11.0", Some(37854), None),
/// Allows exhaustive pattern matching on types that contain uninhabited types.
(active, exhaustive_patterns, "1.13.0", Some(51085), None),
+ /// Allows using `efiapi`, `sysv64` and `win64` as calling convention
+ /// for functions with varargs.
+ (active, extended_varargs_abi_support, "1.65.0", Some(100189), None),
/// Allows defining `extern type`s.
(active, extern_types, "1.23.0", Some(43467), None),
/// Allows the use of `#[ffi_const]` on foreign functions.
(active, half_open_range_patterns_in_slices, "CURRENT_RUSTC_VERSION", Some(67264), None),
/// Allows `if let` guard in match arms.
(active, if_let_guard, "1.47.0", Some(51114), None),
+ /// Allows `impl Trait` as output type in `Fn` traits in return position of functions.
+ (active, impl_trait_in_fn_trait_return, "1.64.0", Some(99697), None),
/// Allows using imported `main` function
(active, imported_main, "1.53.0", Some(28937), None),
/// Allows associated types in inherent impls.
(incomplete, inline_const_pat, "1.58.0", Some(76001), None),
/// Allows using `pointer` and `reference` in intra-doc links
(active, intra_doc_pointers, "1.51.0", Some(80896), None),
- /// Allows `#[instruction_set(_)]` attribute
- (active, isa_attribute, "1.48.0", Some(74727), None),
// Allows setting the threshold for the `large_assignments` lint.
(active, large_assignments, "1.52.0", Some(83518), None),
/// Allows `if/while p && let q = r && ...` chains.
DuplicatesOk, @only_local: true,
),
ungated!(track_caller, Normal, template!(Word), WarnFollowing),
+ ungated!(instruction_set, Normal, template!(List: "set"), ErrorPreceding),
gated!(
no_sanitize, Normal,
template!(List: "address, memory, thread"), DuplicatesOk,
optimize, Normal, template!(List: "size|speed"), ErrorPreceding, optimize_attribute,
experimental!(optimize),
),
- // RFC 2867
- gated!(
- instruction_set, Normal, template!(List: "set"), ErrorPreceding,
- isa_attribute, experimental!(instruction_set)
- ),
gated!(
ffi_returns_twice, Normal, template!(Word), WarnFollowing, experimental!(ffi_returns_twice)
rustc_attr!(rustc_reallocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
rustc_attr!(rustc_deallocator, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
rustc_attr!(rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing, IMPL_DETAIL),
- gated!(
- alloc_error_handler, Normal, template!(Word), WarnFollowing,
- experimental!(alloc_error_handler)
- ),
gated!(
default_lib_allocator, Normal, template!(Word), WarnFollowing, allocator_internals,
experimental!(default_lib_allocator),
}
#[inline]
+ /// This function returns the number of type and const generic params.
+ /// It should only be used for diagnostics.
pub fn num_generic_params(&self) -> usize {
self.args.iter().filter(|arg| !matches!(arg, GenericArg::Lifetime(_))).count()
}
// so it can fetched later.
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct TraitItemId {
- pub def_id: OwnerId,
+ pub owner_id: OwnerId,
}
impl TraitItemId {
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
- HirId::make_owner(self.def_id.def_id)
+ HirId::make_owner(self.owner_id.def_id)
}
}
#[derive(Debug, HashStable_Generic)]
pub struct TraitItem<'hir> {
pub ident: Ident,
- pub def_id: OwnerId,
+ pub owner_id: OwnerId,
pub generics: &'hir Generics<'hir>,
pub kind: TraitItemKind<'hir>,
pub span: Span,
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
- HirId::make_owner(self.def_id.def_id)
+ HirId::make_owner(self.owner_id.def_id)
}
pub fn trait_item_id(&self) -> TraitItemId {
- TraitItemId { def_id: self.def_id }
+ TraitItemId { owner_id: self.owner_id }
}
}
// so it can fetched later.
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct ImplItemId {
- pub def_id: OwnerId,
+ pub owner_id: OwnerId,
}
impl ImplItemId {
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
- HirId::make_owner(self.def_id.def_id)
+ HirId::make_owner(self.owner_id.def_id)
}
}
#[derive(Debug, HashStable_Generic)]
pub struct ImplItem<'hir> {
pub ident: Ident,
- pub def_id: OwnerId,
+ pub owner_id: OwnerId,
pub generics: &'hir Generics<'hir>,
pub kind: ImplItemKind<'hir>,
pub defaultness: Defaultness,
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
- HirId::make_owner(self.def_id.def_id)
+ HirId::make_owner(self.owner_id.def_id)
}
pub fn impl_item_id(&self) -> ImplItemId {
- ImplItemId { def_id: self.def_id }
+ ImplItemId { owner_id: self.owner_id }
}
}
}
final_ty
}
+
+ pub fn find_self_aliases(&self) -> Vec<Span> {
+ use crate::intravisit::Visitor;
+ struct MyVisitor(Vec<Span>);
+ impl<'v> Visitor<'v> for MyVisitor {
+ fn visit_ty(&mut self, t: &'v Ty<'v>) {
+ if matches!(
+ &t.kind,
+ TyKind::Path(QPath::Resolved(
+ _,
+ Path { res: crate::def::Res::SelfTyAlias { .. }, .. },
+ ))
+ ) {
+ self.0.push(t.span);
+ return;
+ }
+ crate::intravisit::walk_ty(self, t);
+ }
+ }
+
+ let mut my_visitor = MyVisitor(vec![]);
+ my_visitor.visit_ty(self);
+ my_visitor.0
+ }
}
/// Not represented directly in the AST; referred to by name through a `ty_path`.
// so it can fetched later.
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, Hash, HashStable_Generic)]
pub struct ItemId {
- pub def_id: OwnerId,
+ pub owner_id: OwnerId,
}
impl ItemId {
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
- HirId::make_owner(self.def_id.def_id)
+ HirId::make_owner(self.owner_id.def_id)
}
}
#[derive(Debug, HashStable_Generic)]
pub struct Item<'hir> {
pub ident: Ident,
- pub def_id: OwnerId,
+ pub owner_id: OwnerId,
pub kind: ItemKind<'hir>,
pub span: Span,
pub vis_span: Span,
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
- HirId::make_owner(self.def_id.def_id)
+ HirId::make_owner(self.owner_id.def_id)
}
pub fn item_id(&self) -> ItemId {
- ItemId { def_id: self.def_id }
+ ItemId { owner_id: self.owner_id }
}
}
// so it can fetched later.
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
pub struct ForeignItemId {
- pub def_id: OwnerId,
+ pub owner_id: OwnerId,
}
impl ForeignItemId {
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
- HirId::make_owner(self.def_id.def_id)
+ HirId::make_owner(self.owner_id.def_id)
}
}
pub struct ForeignItem<'hir> {
pub ident: Ident,
pub kind: ForeignItemKind<'hir>,
- pub def_id: OwnerId,
+ pub owner_id: OwnerId,
pub span: Span,
pub vis_span: Span,
}
#[inline]
pub fn hir_id(&self) -> HirId {
// Items are always HIR owners.
- HirId::make_owner(self.def_id.def_id)
+ HirId::make_owner(self.owner_id.def_id)
}
pub fn foreign_item_id(&self) -> ForeignItemId {
- ForeignItemId { def_id: self.def_id }
+ ForeignItemId { owner_id: self.owner_id }
}
}
pub fn def_id(self) -> OwnerId {
match self {
- OwnerNode::Item(Item { def_id, .. })
- | OwnerNode::TraitItem(TraitItem { def_id, .. })
- | OwnerNode::ImplItem(ImplItem { def_id, .. })
- | OwnerNode::ForeignItem(ForeignItem { def_id, .. }) => *def_id,
+ OwnerNode::Item(Item { owner_id, .. })
+ | OwnerNode::TraitItem(TraitItem { owner_id, .. })
+ | OwnerNode::ImplItem(ImplItem { owner_id, .. })
+ | OwnerNode::ForeignItem(ForeignItem { owner_id, .. }) => *owner_id,
OwnerNode::Crate(..) => crate::CRATE_HIR_ID.owner,
}
}
fn visit_where_predicate(&mut self, predicate: &'v WherePredicate<'v>) {
walk_where_predicate(self, predicate)
}
+ fn visit_fn_ret_ty(&mut self, ret_ty: &'v FnRetTy<'v>) {
+ walk_fn_ret_ty(self, ret_ty)
+ }
fn visit_fn_decl(&mut self, fd: &'v FnDecl<'v>) {
walk_fn_decl(self, fd)
}
walk_inf(self, inf);
}
fn visit_generic_arg(&mut self, generic_arg: &'v GenericArg<'v>) {
- match generic_arg {
- GenericArg::Lifetime(lt) => self.visit_lifetime(lt),
- GenericArg::Type(ty) => self.visit_ty(ty),
- GenericArg::Const(ct) => self.visit_anon_const(&ct.value),
- GenericArg::Infer(inf) => self.visit_infer(inf),
- }
+ walk_generic_arg(self, generic_arg);
}
fn visit_lifetime(&mut self, lifetime: &'v Lifetime) {
walk_lifetime(self, lifetime)
}
}
-pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod<'v>, mod_hir_id: HirId) {
- visitor.visit_id(mod_hir_id);
- for &item_id in module.item_ids {
- visitor.visit_nested_item(item_id);
- }
-}
-
-pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body<'v>) {
- walk_list!(visitor, visit_param, body.params);
- visitor.visit_expr(&body.value);
-}
-
-pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local<'v>) {
- // Intentionally visiting the expr first - the initialization expr
- // dominates the local's definition.
- walk_list!(visitor, visit_expr, &local.init);
- visitor.visit_id(local.hir_id);
- visitor.visit_pat(&local.pat);
- if let Some(els) = local.els {
- visitor.visit_block(els);
- }
- walk_list!(visitor, visit_ty, &local.ty);
-}
-
-pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, ident: Ident) {
- visitor.visit_name(ident.name);
-}
-
-pub fn walk_label<'v, V: Visitor<'v>>(visitor: &mut V, label: &'v Label) {
- visitor.visit_ident(label.ident);
-}
-
-pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
- visitor.visit_id(lifetime.hir_id);
- match lifetime.name {
- LifetimeName::Param(_, ParamName::Plain(ident)) => {
- visitor.visit_ident(ident);
- }
- LifetimeName::Param(_, ParamName::Fresh)
- | LifetimeName::Param(_, ParamName::Error)
- | LifetimeName::Static
- | LifetimeName::Error
- | LifetimeName::ImplicitObjectLifetimeDefault
- | LifetimeName::Infer => {}
- }
-}
-
-pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_ref: &'v PolyTraitRef<'v>) {
- walk_list!(visitor, visit_generic_param, trait_ref.bound_generic_params);
- visitor.visit_trait_ref(&trait_ref.trait_ref);
-}
-
-pub fn walk_trait_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_ref: &'v TraitRef<'v>) {
- visitor.visit_id(trait_ref.hir_ref_id);
- visitor.visit_path(&trait_ref.path, trait_ref.hir_ref_id)
-}
-
pub fn walk_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v Param<'v>) {
visitor.visit_id(param.hir_id);
visitor.visit_pat(¶m.pat);
}
}
-pub fn walk_inline_asm<'v, V: Visitor<'v>>(visitor: &mut V, asm: &'v InlineAsm<'v>, id: HirId) {
- for (op, op_sp) in asm.operands {
- match op {
- InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => {
- visitor.visit_expr(expr)
- }
- InlineAsmOperand::Out { expr, .. } => {
- if let Some(expr) = expr {
- visitor.visit_expr(expr);
- }
- }
- InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
- visitor.visit_expr(in_expr);
- if let Some(out_expr) = out_expr {
- visitor.visit_expr(out_expr);
- }
- }
- InlineAsmOperand::Const { anon_const, .. }
- | InlineAsmOperand::SymFn { anon_const, .. } => visitor.visit_anon_const(anon_const),
- InlineAsmOperand::SymStatic { path, .. } => visitor.visit_qpath(path, id, *op_sp),
- }
- }
-}
-
-pub fn walk_use<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path<'v>, hir_id: HirId) {
- visitor.visit_id(hir_id);
- visitor.visit_path(path, hir_id);
+pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body<'v>) {
+ walk_list!(visitor, visit_param, body.params);
+ visitor.visit_expr(&body.value);
}
-pub fn walk_enum_def<'v, V: Visitor<'v>>(
- visitor: &mut V,
- enum_definition: &'v EnumDef<'v>,
- item_id: HirId,
-) {
- visitor.visit_id(item_id);
- walk_list!(visitor, visit_variant, enum_definition.variants);
+pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, ident: Ident) {
+ visitor.visit_name(ident.name);
}
-pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, variant: &'v Variant<'v>) {
- visitor.visit_ident(variant.ident);
- visitor.visit_id(variant.id);
- visitor.visit_variant_data(&variant.data);
- walk_list!(visitor, visit_anon_const, &variant.disr_expr);
+pub fn walk_mod<'v, V: Visitor<'v>>(visitor: &mut V, module: &'v Mod<'v>, mod_hir_id: HirId) {
+ visitor.visit_id(mod_hir_id);
+ for &item_id in module.item_ids {
+ visitor.visit_nested_item(item_id);
+ }
}
-pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
- visitor.visit_id(typ.hir_id);
+pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v ForeignItem<'v>) {
+ visitor.visit_id(foreign_item.hir_id());
+ visitor.visit_ident(foreign_item.ident);
- match typ.kind {
- TyKind::Slice(ref ty) => visitor.visit_ty(ty),
- TyKind::Ptr(ref mutable_type) => visitor.visit_ty(&mutable_type.ty),
- TyKind::Rptr(ref lifetime, ref mutable_type) => {
- visitor.visit_lifetime(lifetime);
- visitor.visit_ty(&mutable_type.ty)
- }
- TyKind::Never => {}
- TyKind::Tup(tuple_element_types) => {
- walk_list!(visitor, visit_ty, tuple_element_types);
- }
- TyKind::BareFn(ref function_declaration) => {
- walk_list!(visitor, visit_generic_param, function_declaration.generic_params);
- visitor.visit_fn_decl(&function_declaration.decl);
- }
- TyKind::Path(ref qpath) => {
- visitor.visit_qpath(qpath, typ.hir_id, typ.span);
- }
- TyKind::OpaqueDef(item_id, lifetimes, _in_trait) => {
- visitor.visit_nested_item(item_id);
- walk_list!(visitor, visit_generic_arg, lifetimes);
- }
- TyKind::Array(ref ty, ref length) => {
- visitor.visit_ty(ty);
- visitor.visit_array_length(length)
- }
- TyKind::TraitObject(bounds, ref lifetime, _syntax) => {
- for bound in bounds {
- visitor.visit_poly_trait_ref(bound);
+ match foreign_item.kind {
+ ForeignItemKind::Fn(ref function_declaration, param_names, ref generics) => {
+ visitor.visit_generics(generics);
+ visitor.visit_fn_decl(function_declaration);
+ for ¶m_name in param_names {
+ visitor.visit_ident(param_name);
}
- visitor.visit_lifetime(lifetime);
}
- TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression),
- TyKind::Infer | TyKind::Err => {}
+ ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ),
+ ForeignItemKind::Type => (),
}
}
-pub fn walk_inf<'v, V: Visitor<'v>>(visitor: &mut V, inf: &'v InferArg) {
- visitor.visit_id(inf.hir_id);
-}
-
-pub fn walk_qpath<'v, V: Visitor<'v>>(visitor: &mut V, qpath: &'v QPath<'v>, id: HirId) {
- match *qpath {
- QPath::Resolved(ref maybe_qself, ref path) => {
- walk_list!(visitor, visit_ty, maybe_qself);
- visitor.visit_path(path, id)
- }
- QPath::TypeRelative(ref qself, ref segment) => {
- visitor.visit_ty(qself);
- visitor.visit_path_segment(segment);
- }
- QPath::LangItem(..) => {}
+pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local<'v>) {
+ // Intentionally visiting the expr first - the initialization expr
+ // dominates the local's definition.
+ walk_list!(visitor, visit_expr, &local.init);
+ visitor.visit_id(local.hir_id);
+ visitor.visit_pat(&local.pat);
+ if let Some(els) = local.els {
+ visitor.visit_block(els);
}
+ walk_list!(visitor, visit_ty, &local.ty);
}
-pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path<'v>) {
- for segment in path.segments {
- visitor.visit_path_segment(segment);
- }
+pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block<'v>) {
+ visitor.visit_id(block.hir_id);
+ walk_list!(visitor, visit_stmt, block.stmts);
+ walk_list!(visitor, visit_expr, &block.expr);
}
-pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V, segment: &'v PathSegment<'v>) {
- visitor.visit_ident(segment.ident);
- visitor.visit_id(segment.hir_id);
- if let Some(ref args) = segment.args {
- visitor.visit_generic_args(args);
+pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) {
+ visitor.visit_id(statement.hir_id);
+ match statement.kind {
+ StmtKind::Local(ref local) => visitor.visit_local(local),
+ StmtKind::Item(item) => visitor.visit_nested_item(item),
+ StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => {
+ visitor.visit_expr(expression)
+ }
}
}
-pub fn walk_generic_args<'v, V: Visitor<'v>>(visitor: &mut V, generic_args: &'v GenericArgs<'v>) {
- walk_list!(visitor, visit_generic_arg, generic_args.args);
- walk_list!(visitor, visit_assoc_type_binding, generic_args.bindings);
-}
-
-pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(
- visitor: &mut V,
- type_binding: &'v TypeBinding<'v>,
-) {
- visitor.visit_id(type_binding.hir_id);
- visitor.visit_ident(type_binding.ident);
- visitor.visit_generic_args(type_binding.gen_args);
- match type_binding.kind {
- TypeBindingKind::Equality { ref term } => match term {
- Term::Ty(ref ty) => visitor.visit_ty(ty),
- Term::Const(ref c) => visitor.visit_anon_const(c),
- },
- TypeBindingKind::Constraint { bounds } => walk_list!(visitor, visit_param_bound, bounds),
+pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) {
+ visitor.visit_id(arm.hir_id);
+ visitor.visit_pat(&arm.pat);
+ if let Some(ref g) = arm.guard {
+ match g {
+ Guard::If(ref e) => visitor.visit_expr(e),
+ Guard::IfLet(ref l) => {
+ visitor.visit_let_expr(l);
+ }
+ }
}
+ visitor.visit_expr(&arm.body);
}
pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) {
visitor.visit_pat(&field.pat)
}
-pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v ForeignItem<'v>) {
- visitor.visit_id(foreign_item.hir_id());
- visitor.visit_ident(foreign_item.ident);
-
- match foreign_item.kind {
- ForeignItemKind::Fn(ref function_declaration, param_names, ref generics) => {
- visitor.visit_generics(generics);
- visitor.visit_fn_decl(function_declaration);
- for ¶m_name in param_names {
- visitor.visit_ident(param_name);
- }
- }
- ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ),
- ForeignItemKind::Type => (),
+pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen) {
+ match len {
+ &ArrayLen::Infer(hir_id, _span) => visitor.visit_id(hir_id),
+ ArrayLen::Body(c) => visitor.visit_anon_const(c),
}
}
-pub fn walk_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v GenericBound<'v>) {
- match *bound {
- GenericBound::Trait(ref typ, _modifier) => {
- visitor.visit_poly_trait_ref(typ);
- }
- GenericBound::LangItemTrait(_, _span, hir_id, args) => {
- visitor.visit_id(hir_id);
- visitor.visit_generic_args(args);
- }
- GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime),
- }
+pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) {
+ visitor.visit_id(constant.hir_id);
+ visitor.visit_nested_body(constant.body);
+}
+
+pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) {
+ visitor.visit_id(expression.hir_id);
+ match expression.kind {
+ ExprKind::Box(ref subexpression) => visitor.visit_expr(subexpression),
+ ExprKind::Array(subexpressions) => {
+ walk_list!(visitor, visit_expr, subexpressions);
+ }
+ ExprKind::ConstBlock(ref anon_const) => visitor.visit_anon_const(anon_const),
+ ExprKind::Repeat(ref element, ref count) => {
+ visitor.visit_expr(element);
+ visitor.visit_array_length(count)
+ }
+ ExprKind::Struct(ref qpath, fields, ref optional_base) => {
+ visitor.visit_qpath(qpath, expression.hir_id, expression.span);
+ walk_list!(visitor, visit_expr_field, fields);
+ walk_list!(visitor, visit_expr, optional_base);
+ }
+ ExprKind::Tup(subexpressions) => {
+ walk_list!(visitor, visit_expr, subexpressions);
+ }
+ ExprKind::Call(ref callee_expression, arguments) => {
+ visitor.visit_expr(callee_expression);
+ walk_list!(visitor, visit_expr, arguments);
+ }
+ ExprKind::MethodCall(ref segment, receiver, arguments, _) => {
+ visitor.visit_path_segment(segment);
+ visitor.visit_expr(receiver);
+ walk_list!(visitor, visit_expr, arguments);
+ }
+ ExprKind::Binary(_, ref left_expression, ref right_expression) => {
+ visitor.visit_expr(left_expression);
+ visitor.visit_expr(right_expression)
+ }
+ ExprKind::AddrOf(_, _, ref subexpression) | ExprKind::Unary(_, ref subexpression) => {
+ visitor.visit_expr(subexpression)
+ }
+ ExprKind::Cast(ref subexpression, ref typ) | ExprKind::Type(ref subexpression, ref typ) => {
+ visitor.visit_expr(subexpression);
+ visitor.visit_ty(typ)
+ }
+ ExprKind::DropTemps(ref subexpression) => {
+ visitor.visit_expr(subexpression);
+ }
+ ExprKind::Let(ref let_expr) => visitor.visit_let_expr(let_expr),
+ ExprKind::If(ref cond, ref then, ref else_opt) => {
+ visitor.visit_expr(cond);
+ visitor.visit_expr(then);
+ walk_list!(visitor, visit_expr, else_opt);
+ }
+ ExprKind::Loop(ref block, ref opt_label, _, _) => {
+ walk_list!(visitor, visit_label, opt_label);
+ visitor.visit_block(block);
+ }
+ ExprKind::Match(ref subexpression, arms, _) => {
+ visitor.visit_expr(subexpression);
+ walk_list!(visitor, visit_arm, arms);
+ }
+ ExprKind::Closure(&Closure {
+ binder: _,
+ bound_generic_params,
+ fn_decl,
+ body,
+ capture_clause: _,
+ fn_decl_span: _,
+ movability: _,
+ }) => {
+ walk_list!(visitor, visit_generic_param, bound_generic_params);
+ visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, expression.hir_id)
+ }
+ ExprKind::Block(ref block, ref opt_label) => {
+ walk_list!(visitor, visit_label, opt_label);
+ visitor.visit_block(block);
+ }
+ ExprKind::Assign(ref lhs, ref rhs, _) => {
+ visitor.visit_expr(rhs);
+ visitor.visit_expr(lhs)
+ }
+ ExprKind::AssignOp(_, ref left_expression, ref right_expression) => {
+ visitor.visit_expr(right_expression);
+ visitor.visit_expr(left_expression);
+ }
+ ExprKind::Field(ref subexpression, ident) => {
+ visitor.visit_expr(subexpression);
+ visitor.visit_ident(ident);
+ }
+ ExprKind::Index(ref main_expression, ref index_expression) => {
+ visitor.visit_expr(main_expression);
+ visitor.visit_expr(index_expression)
+ }
+ ExprKind::Path(ref qpath) => {
+ visitor.visit_qpath(qpath, expression.hir_id, expression.span);
+ }
+ ExprKind::Break(ref destination, ref opt_expr) => {
+ walk_list!(visitor, visit_label, &destination.label);
+ walk_list!(visitor, visit_expr, opt_expr);
+ }
+ ExprKind::Continue(ref destination) => {
+ walk_list!(visitor, visit_label, &destination.label);
+ }
+ ExprKind::Ret(ref optional_expression) => {
+ walk_list!(visitor, visit_expr, optional_expression);
+ }
+ ExprKind::InlineAsm(ref asm) => {
+ visitor.visit_inline_asm(asm, expression.hir_id);
+ }
+ ExprKind::Yield(ref subexpression, _) => {
+ visitor.visit_expr(subexpression);
+ }
+ ExprKind::Lit(_) | ExprKind::Err => {}
+ }
+}
+
+pub fn walk_let_expr<'v, V: Visitor<'v>>(visitor: &mut V, let_expr: &'v Let<'v>) {
+ // match the visit order in walk_local
+ visitor.visit_expr(let_expr.init);
+ visitor.visit_id(let_expr.hir_id);
+ visitor.visit_pat(let_expr.pat);
+ walk_list!(visitor, visit_ty, let_expr.ty);
+}
+
+pub fn walk_expr_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v ExprField<'v>) {
+ visitor.visit_id(field.hir_id);
+ visitor.visit_ident(field.ident);
+ visitor.visit_expr(&field.expr)
+}
+
+pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty<'v>) {
+ visitor.visit_id(typ.hir_id);
+
+ match typ.kind {
+ TyKind::Slice(ref ty) => visitor.visit_ty(ty),
+ TyKind::Ptr(ref mutable_type) => visitor.visit_ty(&mutable_type.ty),
+ TyKind::Rptr(ref lifetime, ref mutable_type) => {
+ visitor.visit_lifetime(lifetime);
+ visitor.visit_ty(&mutable_type.ty)
+ }
+ TyKind::Never => {}
+ TyKind::Tup(tuple_element_types) => {
+ walk_list!(visitor, visit_ty, tuple_element_types);
+ }
+ TyKind::BareFn(ref function_declaration) => {
+ walk_list!(visitor, visit_generic_param, function_declaration.generic_params);
+ visitor.visit_fn_decl(&function_declaration.decl);
+ }
+ TyKind::Path(ref qpath) => {
+ visitor.visit_qpath(qpath, typ.hir_id, typ.span);
+ }
+ TyKind::OpaqueDef(item_id, lifetimes, _in_trait) => {
+ visitor.visit_nested_item(item_id);
+ walk_list!(visitor, visit_generic_arg, lifetimes);
+ }
+ TyKind::Array(ref ty, ref length) => {
+ visitor.visit_ty(ty);
+ visitor.visit_array_length(length)
+ }
+ TyKind::TraitObject(bounds, ref lifetime, _syntax) => {
+ for bound in bounds {
+ visitor.visit_poly_trait_ref(bound);
+ }
+ visitor.visit_lifetime(lifetime);
+ }
+ TyKind::Typeof(ref expression) => visitor.visit_anon_const(expression),
+ TyKind::Infer | TyKind::Err => {}
+ }
}
pub fn walk_generic_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v GenericParam<'v>) {
}
}
-pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FnRetTy<'v>) {
- if let FnRetTy::Return(ref output_ty) = *ret_ty {
- visitor.visit_ty(output_ty)
- }
-}
-
pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl<'v>) {
for ty in function_declaration.inputs {
visitor.visit_ty(ty)
}
- walk_fn_ret_ty(visitor, &function_declaration.output)
+ visitor.visit_fn_ret_ty(&function_declaration.output)
}
-pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'v>) {
- match function_kind {
- FnKind::ItemFn(_, generics, ..) => {
- visitor.visit_generics(generics);
- }
- FnKind::Closure | FnKind::Method(..) => {}
+pub fn walk_fn_ret_ty<'v, V: Visitor<'v>>(visitor: &mut V, ret_ty: &'v FnRetTy<'v>) {
+ if let FnRetTy::Return(ref output_ty) = *ret_ty {
+ visitor.visit_ty(output_ty)
}
}
visitor.visit_nested_body(body_id)
}
+pub fn walk_fn_kind<'v, V: Visitor<'v>>(visitor: &mut V, function_kind: FnKind<'v>) {
+ match function_kind {
+ FnKind::ItemFn(_, generics, ..) => {
+ visitor.visit_generics(generics);
+ }
+ FnKind::Closure | FnKind::Method(..) => {}
+ }
+}
+
+pub fn walk_use<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path<'v>, hir_id: HirId) {
+ visitor.visit_id(hir_id);
+ visitor.visit_path(path, hir_id);
+}
+
pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem<'v>) {
// N.B., deliberately force a compilation error if/when new fields are added.
- let TraitItem { ident, generics, ref defaultness, ref kind, span, def_id: _ } = *trait_item;
+ let TraitItem { ident, generics, ref defaultness, ref kind, span, owner_id: _ } = *trait_item;
let hir_id = trait_item.hir_id();
visitor.visit_ident(ident);
visitor.visit_generics(&generics);
pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem<'v>) {
// N.B., deliberately force a compilation error if/when new fields are added.
let ImplItem {
- def_id: _,
+ owner_id: _,
ident,
ref generics,
ref kind,
visitor.visit_associated_item_kind(kind);
}
+pub fn walk_trait_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_ref: &'v TraitRef<'v>) {
+ visitor.visit_id(trait_ref.hir_ref_id);
+ visitor.visit_path(&trait_ref.path, trait_ref.hir_ref_id)
+}
+
+pub fn walk_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v GenericBound<'v>) {
+ match *bound {
+ GenericBound::Trait(ref typ, _modifier) => {
+ visitor.visit_poly_trait_ref(typ);
+ }
+ GenericBound::LangItemTrait(_, _span, hir_id, args) => {
+ visitor.visit_id(hir_id);
+ visitor.visit_generic_args(args);
+ }
+ GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime),
+ }
+}
+
+pub fn walk_poly_trait_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_ref: &'v PolyTraitRef<'v>) {
+ walk_list!(visitor, visit_generic_param, trait_ref.bound_generic_params);
+ visitor.visit_trait_ref(&trait_ref.trait_ref);
+}
+
pub fn walk_struct_def<'v, V: Visitor<'v>>(
visitor: &mut V,
struct_definition: &'v VariantData<'v>,
visitor.visit_ty(&field.ty);
}
-pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block<'v>) {
- visitor.visit_id(block.hir_id);
- walk_list!(visitor, visit_stmt, block.stmts);
- walk_list!(visitor, visit_expr, &block.expr);
+pub fn walk_enum_def<'v, V: Visitor<'v>>(
+ visitor: &mut V,
+ enum_definition: &'v EnumDef<'v>,
+ item_id: HirId,
+) {
+ visitor.visit_id(item_id);
+ walk_list!(visitor, visit_variant, enum_definition.variants);
}
-pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt<'v>) {
- visitor.visit_id(statement.hir_id);
- match statement.kind {
- StmtKind::Local(ref local) => visitor.visit_local(local),
- StmtKind::Item(item) => visitor.visit_nested_item(item),
- StmtKind::Expr(ref expression) | StmtKind::Semi(ref expression) => {
- visitor.visit_expr(expression)
- }
- }
+pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, variant: &'v Variant<'v>) {
+ visitor.visit_ident(variant.ident);
+ visitor.visit_id(variant.id);
+ visitor.visit_variant_data(&variant.data);
+ walk_list!(visitor, visit_anon_const, &variant.disr_expr);
}
-pub fn walk_array_len<'v, V: Visitor<'v>>(visitor: &mut V, len: &'v ArrayLen) {
- match len {
- &ArrayLen::Infer(hir_id, _span) => visitor.visit_id(hir_id),
- ArrayLen::Body(c) => visitor.visit_anon_const(c),
- }
+pub fn walk_label<'v, V: Visitor<'v>>(visitor: &mut V, label: &'v Label) {
+ visitor.visit_ident(label.ident);
}
-pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) {
- visitor.visit_id(constant.hir_id);
- visitor.visit_nested_body(constant.body);
+pub fn walk_inf<'v, V: Visitor<'v>>(visitor: &mut V, inf: &'v InferArg) {
+ visitor.visit_id(inf.hir_id);
}
-pub fn walk_let_expr<'v, V: Visitor<'v>>(visitor: &mut V, let_expr: &'v Let<'v>) {
- // match the visit order in walk_local
- visitor.visit_expr(let_expr.init);
- visitor.visit_id(let_expr.hir_id);
- visitor.visit_pat(let_expr.pat);
- walk_list!(visitor, visit_ty, let_expr.ty);
+pub fn walk_generic_arg<'v, V: Visitor<'v>>(visitor: &mut V, generic_arg: &'v GenericArg<'v>) {
+ match generic_arg {
+ GenericArg::Lifetime(lt) => visitor.visit_lifetime(lt),
+ GenericArg::Type(ty) => visitor.visit_ty(ty),
+ GenericArg::Const(ct) => visitor.visit_anon_const(&ct.value),
+ GenericArg::Infer(inf) => visitor.visit_infer(inf),
+ }
}
-pub fn walk_expr_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v ExprField<'v>) {
- visitor.visit_id(field.hir_id);
- visitor.visit_ident(field.ident);
- visitor.visit_expr(&field.expr)
+pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) {
+ visitor.visit_id(lifetime.hir_id);
+ match lifetime.name {
+ LifetimeName::Param(_, ParamName::Plain(ident)) => {
+ visitor.visit_ident(ident);
+ }
+ LifetimeName::Param(_, ParamName::Fresh)
+ | LifetimeName::Param(_, ParamName::Error)
+ | LifetimeName::Static
+ | LifetimeName::Error
+ | LifetimeName::ImplicitObjectLifetimeDefault
+ | LifetimeName::Infer => {}
+ }
}
-pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) {
- visitor.visit_id(expression.hir_id);
- match expression.kind {
- ExprKind::Box(ref subexpression) => visitor.visit_expr(subexpression),
- ExprKind::Array(subexpressions) => {
- walk_list!(visitor, visit_expr, subexpressions);
- }
- ExprKind::ConstBlock(ref anon_const) => visitor.visit_anon_const(anon_const),
- ExprKind::Repeat(ref element, ref count) => {
- visitor.visit_expr(element);
- visitor.visit_array_length(count)
- }
- ExprKind::Struct(ref qpath, fields, ref optional_base) => {
- visitor.visit_qpath(qpath, expression.hir_id, expression.span);
- walk_list!(visitor, visit_expr_field, fields);
- walk_list!(visitor, visit_expr, optional_base);
- }
- ExprKind::Tup(subexpressions) => {
- walk_list!(visitor, visit_expr, subexpressions);
- }
- ExprKind::Call(ref callee_expression, arguments) => {
- visitor.visit_expr(callee_expression);
- walk_list!(visitor, visit_expr, arguments);
+pub fn walk_qpath<'v, V: Visitor<'v>>(visitor: &mut V, qpath: &'v QPath<'v>, id: HirId) {
+ match *qpath {
+ QPath::Resolved(ref maybe_qself, ref path) => {
+ walk_list!(visitor, visit_ty, maybe_qself);
+ visitor.visit_path(path, id)
}
- ExprKind::MethodCall(ref segment, receiver, arguments, _) => {
+ QPath::TypeRelative(ref qself, ref segment) => {
+ visitor.visit_ty(qself);
visitor.visit_path_segment(segment);
- visitor.visit_expr(receiver);
- walk_list!(visitor, visit_expr, arguments);
- }
- ExprKind::Binary(_, ref left_expression, ref right_expression) => {
- visitor.visit_expr(left_expression);
- visitor.visit_expr(right_expression)
}
- ExprKind::AddrOf(_, _, ref subexpression) | ExprKind::Unary(_, ref subexpression) => {
- visitor.visit_expr(subexpression)
- }
- ExprKind::Cast(ref subexpression, ref typ) | ExprKind::Type(ref subexpression, ref typ) => {
- visitor.visit_expr(subexpression);
- visitor.visit_ty(typ)
- }
- ExprKind::DropTemps(ref subexpression) => {
- visitor.visit_expr(subexpression);
- }
- ExprKind::Let(ref let_expr) => visitor.visit_let_expr(let_expr),
- ExprKind::If(ref cond, ref then, ref else_opt) => {
- visitor.visit_expr(cond);
- visitor.visit_expr(then);
- walk_list!(visitor, visit_expr, else_opt);
- }
- ExprKind::Loop(ref block, ref opt_label, _, _) => {
- walk_list!(visitor, visit_label, opt_label);
- visitor.visit_block(block);
- }
- ExprKind::Match(ref subexpression, arms, _) => {
- visitor.visit_expr(subexpression);
- walk_list!(visitor, visit_arm, arms);
- }
- ExprKind::Closure(&Closure {
- binder: _,
- bound_generic_params,
- fn_decl,
- body,
- capture_clause: _,
- fn_decl_span: _,
- movability: _,
- }) => {
- walk_list!(visitor, visit_generic_param, bound_generic_params);
- visitor.visit_fn(FnKind::Closure, fn_decl, body, expression.span, expression.hir_id)
- }
- ExprKind::Block(ref block, ref opt_label) => {
- walk_list!(visitor, visit_label, opt_label);
- visitor.visit_block(block);
- }
- ExprKind::Assign(ref lhs, ref rhs, _) => {
- visitor.visit_expr(rhs);
- visitor.visit_expr(lhs)
- }
- ExprKind::AssignOp(_, ref left_expression, ref right_expression) => {
- visitor.visit_expr(right_expression);
- visitor.visit_expr(left_expression);
- }
- ExprKind::Field(ref subexpression, ident) => {
- visitor.visit_expr(subexpression);
- visitor.visit_ident(ident);
- }
- ExprKind::Index(ref main_expression, ref index_expression) => {
- visitor.visit_expr(main_expression);
- visitor.visit_expr(index_expression)
- }
- ExprKind::Path(ref qpath) => {
- visitor.visit_qpath(qpath, expression.hir_id, expression.span);
- }
- ExprKind::Break(ref destination, ref opt_expr) => {
- walk_list!(visitor, visit_label, &destination.label);
- walk_list!(visitor, visit_expr, opt_expr);
- }
- ExprKind::Continue(ref destination) => {
- walk_list!(visitor, visit_label, &destination.label);
- }
- ExprKind::Ret(ref optional_expression) => {
- walk_list!(visitor, visit_expr, optional_expression);
- }
- ExprKind::InlineAsm(ref asm) => {
- visitor.visit_inline_asm(asm, expression.hir_id);
- }
- ExprKind::Yield(ref subexpression, _) => {
- visitor.visit_expr(subexpression);
- }
- ExprKind::Lit(_) | ExprKind::Err => {}
+ QPath::LangItem(..) => {}
}
}
-pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm<'v>) {
- visitor.visit_id(arm.hir_id);
- visitor.visit_pat(&arm.pat);
- if let Some(ref g) = arm.guard {
- match g {
- Guard::If(ref e) => visitor.visit_expr(e),
- Guard::IfLet(ref l) => {
- visitor.visit_let_expr(l);
- }
- }
+pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path<'v>) {
+ for segment in path.segments {
+ visitor.visit_path_segment(segment);
+ }
+}
+
+pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V, segment: &'v PathSegment<'v>) {
+ visitor.visit_ident(segment.ident);
+ visitor.visit_id(segment.hir_id);
+ if let Some(ref args) = segment.args {
+ visitor.visit_generic_args(args);
+ }
+}
+
+pub fn walk_generic_args<'v, V: Visitor<'v>>(visitor: &mut V, generic_args: &'v GenericArgs<'v>) {
+ walk_list!(visitor, visit_generic_arg, generic_args.args);
+ walk_list!(visitor, visit_assoc_type_binding, generic_args.bindings);
+}
+
+pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(
+ visitor: &mut V,
+ type_binding: &'v TypeBinding<'v>,
+) {
+ visitor.visit_id(type_binding.hir_id);
+ visitor.visit_ident(type_binding.ident);
+ visitor.visit_generic_args(type_binding.gen_args);
+ match type_binding.kind {
+ TypeBindingKind::Equality { ref term } => match term {
+ Term::Ty(ref ty) => visitor.visit_ty(ty),
+ Term::Const(ref c) => visitor.visit_anon_const(c),
+ },
+ TypeBindingKind::Constraint { bounds } => walk_list!(visitor, visit_param_bound, bounds),
}
- visitor.visit_expr(&arm.body);
}
pub fn walk_associated_item_kind<'v, V: Visitor<'v>>(_: &mut V, _: &'v AssocItemKind) {
// the right thing to do, should content be added in the future,
// would be to walk it.
}
+
+pub fn walk_inline_asm<'v, V: Visitor<'v>>(visitor: &mut V, asm: &'v InlineAsm<'v>, id: HirId) {
+ for (op, op_sp) in asm.operands {
+ match op {
+ InlineAsmOperand::In { expr, .. } | InlineAsmOperand::InOut { expr, .. } => {
+ visitor.visit_expr(expr)
+ }
+ InlineAsmOperand::Out { expr, .. } => {
+ if let Some(expr) = expr {
+ visitor.visit_expr(expr);
+ }
+ }
+ InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
+ visitor.visit_expr(in_expr);
+ if let Some(out_expr) = out_expr {
+ visitor.visit_expr(out_expr);
+ }
+ }
+ InlineAsmOperand::Const { anon_const, .. }
+ | InlineAsmOperand::SymFn { anon_const, .. } => visitor.visit_anon_const(anon_const),
+ InlineAsmOperand::SymStatic { path, .. } => visitor.visit_qpath(path, id, *op_sp),
+ }
+ }
+}
use crate::{MethodKind, Target};
use rustc_ast as ast;
-use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_macros::HashStable_Generic;
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::Span;
-use std::sync::LazyLock;
-
-pub enum LangItemGroup {
- Op,
- Fn,
+/// All of the language items, defined or not.
+/// Defined lang items can come from the current crate or its dependencies.
+#[derive(HashStable_Generic, Debug)]
+pub struct LanguageItems {
+ /// Mappings from lang items to their possibly found [`DefId`]s.
+ /// The index corresponds to the order in [`LangItem`].
+ items: [Option<DefId>; std::mem::variant_count::<LangItem>()],
+ /// Lang items that were not found during collection.
+ pub missing: Vec<LangItem>,
}
-const NUM_GROUPS: usize = 2;
+impl LanguageItems {
+ /// Construct an empty collection of lang items and no missing ones.
+ pub fn new() -> Self {
+ Self { items: [None; std::mem::variant_count::<LangItem>()], missing: Vec::new() }
+ }
+
+ pub fn get(&self, item: LangItem) -> Option<DefId> {
+ self.items[item as usize]
+ }
-macro_rules! expand_group {
- () => {
- None
- };
- ($group:expr) => {
- Some($group)
- };
+ pub fn set(&mut self, item: LangItem, def_id: DefId) {
+ self.items[item as usize] = Some(def_id);
+ }
+
+ /// Requires that a given `LangItem` was bound and returns the corresponding `DefId`.
+ /// If it wasn't bound, e.g. due to a missing `#[lang = "<it.name()>"]`,
+ /// returns an error encapsulating the `LangItem`.
+ pub fn require(&self, it: LangItem) -> Result<DefId, LangItemError> {
+ self.get(it).ok_or_else(|| LangItemError(it))
+ }
+
+ pub fn iter<'a>(&'a self) -> impl Iterator<Item = (LangItem, DefId)> + 'a {
+ self.items
+ .iter()
+ .enumerate()
+ .filter_map(|(i, id)| id.map(|id| (LangItem::from_u32(i as u32).unwrap(), id)))
+ }
}
// The actual lang items defined come at the end of this file in one handy table.
// So you probably just want to nip down to the end.
macro_rules! language_item_table {
(
- $( $(#[$attr:meta])* $variant:ident $($group:expr)?, $module:ident :: $name:ident, $method:ident, $target:expr, $generics:expr; )*
+ $( $(#[$attr:meta])* $variant:ident, $module:ident :: $name:ident, $method:ident, $target:expr, $generics:expr; )*
) => {
enum_from_u32! {
}
}
- /// The [group](LangItemGroup) that this lang item belongs to,
- /// or `None` if it doesn't belong to a group.
- pub fn group(self) -> Option<LangItemGroup> {
- use LangItemGroup::*;
+ /// Opposite of [`LangItem::name`]
+ pub fn from_name(name: Symbol) -> Option<Self> {
+ match name {
+ $( $module::$name => Some(LangItem::$variant), )*
+ _ => None,
+ }
+ }
+
+ pub fn target(self) -> Target {
match self {
- $( LangItem::$variant => expand_group!($($group)*), )*
+ $( LangItem::$variant => $target, )*
}
}
}
}
- /// All of the language items, defined or not.
- /// Defined lang items can come from the current crate or its dependencies.
- #[derive(HashStable_Generic, Debug)]
- pub struct LanguageItems {
- /// Mappings from lang items to their possibly found [`DefId`]s.
- /// The index corresponds to the order in [`LangItem`].
- pub items: Vec<Option<DefId>>,
- /// Lang items that were not found during collection.
- pub missing: Vec<LangItem>,
- /// Mapping from [`LangItemGroup`] discriminants to all
- /// [`DefId`]s of lang items in that group.
- pub groups: [Vec<DefId>; NUM_GROUPS],
- }
-
impl LanguageItems {
- /// Construct an empty collection of lang items and no missing ones.
- pub fn new() -> Self {
- fn init_none(_: LangItem) -> Option<DefId> { None }
- const EMPTY: Vec<DefId> = Vec::new();
-
- Self {
- items: vec![$(init_none(LangItem::$variant)),*],
- missing: Vec::new(),
- groups: [EMPTY; NUM_GROUPS],
- }
- }
-
- /// Returns the mappings to the possibly found `DefId`s for each lang item.
- pub fn items(&self) -> &[Option<DefId>] {
- &*self.items
- }
-
- /// Requires that a given `LangItem` was bound and returns the corresponding `DefId`.
- /// If it wasn't bound, e.g. due to a missing `#[lang = "<it.name()>"]`,
- /// returns an error encapsulating the `LangItem`.
- pub fn require(&self, it: LangItem) -> Result<DefId, LangItemError> {
- self.items[it as usize].ok_or_else(|| LangItemError(it))
- }
-
- /// Returns the [`DefId`]s of all lang items in a group.
- pub fn group(&self, group: LangItemGroup) -> &[DefId] {
- self.groups[group as usize].as_ref()
- }
-
$(
#[doc = concat!("Returns the [`DefId`] of the `", stringify!($name), "` lang item if it is defined.")]
pub fn $method(&self) -> Option<DefId> {
}
)*
}
-
- /// A mapping from the name of the lang item to its order and the form it must be of.
- pub static ITEM_REFS: LazyLock<FxIndexMap<Symbol, (usize, Target)>> = LazyLock::new(|| {
- let mut item_refs = FxIndexMap::default();
- $( item_refs.insert($module::$name, (LangItem::$variant as usize, $target)); )*
- item_refs
- });
-
-// End of the macro
}
}
}
/// Extracts the first `lang = "$name"` out of a list of attributes.
-/// The attributes `#[panic_handler]` and `#[alloc_error_handler]`
-/// are also extracted out when found.
+/// The `#[panic_handler]` attribute is also extracted out when found.
pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
attrs.iter().find_map(|attr| {
Some(match attr {
_ if attr.has_name(sym::lang) => (attr.value_str()?, attr.span),
_ if attr.has_name(sym::panic_handler) => (sym::panic_impl, attr.span),
- _ if attr.has_name(sym::alloc_error_handler) => (sym::oom, attr.span),
_ => return None,
})
})
TransmuteOpts, sym::transmute_opts, transmute_opts, Target::Struct, GenericRequirement::Exact(0);
TransmuteTrait, sym::transmute_trait, transmute_trait, Target::Trait, GenericRequirement::Exact(3);
- Add(Op), sym::add, add_trait, Target::Trait, GenericRequirement::Exact(1);
- Sub(Op), sym::sub, sub_trait, Target::Trait, GenericRequirement::Exact(1);
- Mul(Op), sym::mul, mul_trait, Target::Trait, GenericRequirement::Exact(1);
- Div(Op), sym::div, div_trait, Target::Trait, GenericRequirement::Exact(1);
- Rem(Op), sym::rem, rem_trait, Target::Trait, GenericRequirement::Exact(1);
- Neg(Op), sym::neg, neg_trait, Target::Trait, GenericRequirement::Exact(0);
- Not(Op), sym::not, not_trait, Target::Trait, GenericRequirement::Exact(0);
- BitXor(Op), sym::bitxor, bitxor_trait, Target::Trait, GenericRequirement::Exact(1);
- BitAnd(Op), sym::bitand, bitand_trait, Target::Trait, GenericRequirement::Exact(1);
- BitOr(Op), sym::bitor, bitor_trait, Target::Trait, GenericRequirement::Exact(1);
- Shl(Op), sym::shl, shl_trait, Target::Trait, GenericRequirement::Exact(1);
- Shr(Op), sym::shr, shr_trait, Target::Trait, GenericRequirement::Exact(1);
- AddAssign(Op), sym::add_assign, add_assign_trait, Target::Trait, GenericRequirement::Exact(1);
- SubAssign(Op), sym::sub_assign, sub_assign_trait, Target::Trait, GenericRequirement::Exact(1);
- MulAssign(Op), sym::mul_assign, mul_assign_trait, Target::Trait, GenericRequirement::Exact(1);
- DivAssign(Op), sym::div_assign, div_assign_trait, Target::Trait, GenericRequirement::Exact(1);
- RemAssign(Op), sym::rem_assign, rem_assign_trait, Target::Trait, GenericRequirement::Exact(1);
- BitXorAssign(Op), sym::bitxor_assign, bitxor_assign_trait, Target::Trait, GenericRequirement::Exact(1);
- BitAndAssign(Op), sym::bitand_assign, bitand_assign_trait, Target::Trait, GenericRequirement::Exact(1);
- BitOrAssign(Op), sym::bitor_assign, bitor_assign_trait, Target::Trait, GenericRequirement::Exact(1);
- ShlAssign(Op), sym::shl_assign, shl_assign_trait, Target::Trait, GenericRequirement::Exact(1);
- ShrAssign(Op), sym::shr_assign, shr_assign_trait, Target::Trait, GenericRequirement::Exact(1);
- Index(Op), sym::index, index_trait, Target::Trait, GenericRequirement::Exact(1);
- IndexMut(Op), sym::index_mut, index_mut_trait, Target::Trait, GenericRequirement::Exact(1);
+ Add, sym::add, add_trait, Target::Trait, GenericRequirement::Exact(1);
+ Sub, sym::sub, sub_trait, Target::Trait, GenericRequirement::Exact(1);
+ Mul, sym::mul, mul_trait, Target::Trait, GenericRequirement::Exact(1);
+ Div, sym::div, div_trait, Target::Trait, GenericRequirement::Exact(1);
+ Rem, sym::rem, rem_trait, Target::Trait, GenericRequirement::Exact(1);
+ Neg, sym::neg, neg_trait, Target::Trait, GenericRequirement::Exact(0);
+ Not, sym::not, not_trait, Target::Trait, GenericRequirement::Exact(0);
+ BitXor, sym::bitxor, bitxor_trait, Target::Trait, GenericRequirement::Exact(1);
+ BitAnd, sym::bitand, bitand_trait, Target::Trait, GenericRequirement::Exact(1);
+ BitOr, sym::bitor, bitor_trait, Target::Trait, GenericRequirement::Exact(1);
+ Shl, sym::shl, shl_trait, Target::Trait, GenericRequirement::Exact(1);
+ Shr, sym::shr, shr_trait, Target::Trait, GenericRequirement::Exact(1);
+ AddAssign, sym::add_assign, add_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ SubAssign, sym::sub_assign, sub_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ MulAssign, sym::mul_assign, mul_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ DivAssign, sym::div_assign, div_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ RemAssign, sym::rem_assign, rem_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ BitXorAssign, sym::bitxor_assign, bitxor_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ BitAndAssign, sym::bitand_assign, bitand_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ BitOrAssign, sym::bitor_assign, bitor_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ ShlAssign, sym::shl_assign, shl_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ ShrAssign, sym::shr_assign, shr_assign_trait, Target::Trait, GenericRequirement::Exact(1);
+ Index, sym::index, index_trait, Target::Trait, GenericRequirement::Exact(1);
+ IndexMut, sym::index_mut, index_mut_trait, Target::Trait, GenericRequirement::Exact(1);
UnsafeCell, sym::unsafe_cell, unsafe_cell_type, Target::Struct, GenericRequirement::None;
VaList, sym::va_list, va_list, Target::Struct, GenericRequirement::None;
DerefTarget, sym::deref_target, deref_target, Target::AssocTy, GenericRequirement::None;
Receiver, sym::receiver, receiver_trait, Target::Trait, GenericRequirement::None;
- Fn(Fn), kw::Fn, fn_trait, Target::Trait, GenericRequirement::Exact(1);
- FnMut(Fn), sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1);
- FnOnce(Fn), sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1);
+ Fn, kw::Fn, fn_trait, Target::Trait, GenericRequirement::Exact(1);
+ FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1);
+ FnOnce, sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1);
FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None;
Unpin, sym::unpin, unpin_trait, Target::Trait, GenericRequirement::None;
Pin, sym::pin, pin_type, Target::Struct, GenericRequirement::None;
- PartialEq(Op), sym::eq, eq_trait, Target::Trait, GenericRequirement::Exact(1);
- PartialOrd(Op), sym::partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1);
+ PartialEq, sym::eq, eq_trait, Target::Trait, GenericRequirement::Exact(1);
+ PartialOrd, sym::partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1);
// A number of panic-related lang items. The `panic` item corresponds to divide-by-zero and
// various panic cases with `match`. The `panic_bounds_check` item is for indexing arrays.
ExchangeMalloc, sym::exchange_malloc, exchange_malloc_fn, Target::Fn, GenericRequirement::None;
BoxFree, sym::box_free, box_free_fn, Target::Fn, GenericRequirement::Minimum(1);
DropInPlace, sym::drop_in_place, drop_in_place_fn, Target::Fn, GenericRequirement::Minimum(1);
- Oom, sym::oom, oom, Target::Fn, GenericRequirement::None;
AllocLayout, sym::alloc_layout, alloc_layout, Target::Struct, GenericRequirement::None;
Start, sym::start, start_fn, Target::Fn, GenericRequirement::Exact(1);
Minimum(usize),
Exact(usize),
}
+
+pub static FN_TRAITS: &'static [LangItem] = &[LangItem::Fn, LangItem::FnMut, LangItem::FnOnce];
+
+pub static OPERATORS: &'static [LangItem] = &[
+ LangItem::Add,
+ LangItem::Sub,
+ LangItem::Mul,
+ LangItem::Div,
+ LangItem::Rem,
+ LangItem::Neg,
+ LangItem::Not,
+ LangItem::BitXor,
+ LangItem::BitAnd,
+ LangItem::BitOr,
+ LangItem::Shl,
+ LangItem::Shr,
+ LangItem::AddAssign,
+ LangItem::SubAssign,
+ LangItem::MulAssign,
+ LangItem::DivAssign,
+ LangItem::RemAssign,
+ LangItem::BitXorAssign,
+ LangItem::BitAndAssign,
+ LangItem::BitOrAssign,
+ LangItem::ShlAssign,
+ LangItem::ShrAssign,
+ LangItem::Index,
+ LangItem::IndexMut,
+ LangItem::PartialEq,
+ LangItem::PartialOrd,
+];
#![feature(associated_type_defaults)]
#![feature(closure_track_caller)]
#![feature(const_btree_len)]
-#![feature(once_cell)]
#![feature(min_specialization)]
#![feature(never_type)]
#![feature(rustc_attrs)]
+#![feature(variant_count)]
#![recursion_limit = "256"]
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
#[inline]
fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
- self.def_id.def_id.to_stable_hash_key(hcx)
+ self.owner_id.def_id.to_stable_hash_key(hcx)
}
}
#[inline]
fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
- self.def_id.def_id.to_stable_hash_key(hcx)
+ self.owner_id.def_id.to_stable_hash_key(hcx)
}
}
#[inline]
fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
- self.def_id.def_id.to_stable_hash_key(hcx)
+ self.owner_id.def_id.to_stable_hash_key(hcx)
}
}
#[inline]
fn to_stable_hash_key(&self, hcx: &HirCtx) -> DefPathHash {
- self.def_id.def_id.to_stable_hash_key(hcx)
+ self.owner_id.def_id.to_stable_hash_key(hcx)
}
}
//! Validity checking for weak lang items
-use crate::def_id::DefId;
-use crate::{lang_items, LangItem, LanguageItems};
+use crate::LangItem;
-use rustc_ast as ast;
-use rustc_data_structures::fx::FxIndexMap;
use rustc_span::symbol::{sym, Symbol};
-use std::sync::LazyLock;
-
macro_rules! weak_lang_items {
- ($($name:ident, $item:ident, $sym:ident;)*) => (
-
-pub static WEAK_ITEMS_REFS: LazyLock<FxIndexMap<Symbol, LangItem>> = LazyLock::new(|| {
- let mut map = FxIndexMap::default();
- $(map.insert(sym::$name, LangItem::$item);)*
- map
-});
-
-pub static WEAK_ITEMS_SYMBOLS: LazyLock<FxIndexMap<LangItem, Symbol>> = LazyLock::new(|| {
- let mut map = FxIndexMap::default();
- $(map.insert(LangItem::$item, sym::$sym);)*
- map
-});
-
-pub fn link_name(attrs: &[ast::Attribute]) -> Option<Symbol>
-{
- lang_items::extract(attrs).and_then(|(name, _)| {
- $(if name == sym::$name {
- Some(sym::$sym)
- } else)* {
- None
+ ($($item:ident, $sym:ident;)*) => {
+ pub static WEAK_LANG_ITEMS: &[LangItem] = &[$(LangItem::$item,)*];
+
+ impl LangItem {
+ pub fn is_weak(self) -> bool {
+ matches!(self, $(LangItem::$item)|*)
+ }
+
+ pub fn link_name(self) -> Option<Symbol> {
+ match self {
+ $( LangItem::$item => Some(sym::$sym),)*
+ _ => None,
+ }
+ }
}
- })
-}
-
-impl LanguageItems {
- pub fn is_weak_lang_item(&self, item_def_id: DefId) -> bool {
- let did = Some(item_def_id);
-
- $(self.$name() == did)||*
}
}
-) }
-
weak_lang_items! {
- panic_impl, PanicImpl, rust_begin_unwind;
- eh_personality, EhPersonality, rust_eh_personality;
- eh_catch_typeinfo, EhCatchTypeinfo, rust_eh_catch_typeinfo;
- oom, Oom, rust_oom;
+ PanicImpl, rust_begin_unwind;
+ EhPersonality, rust_eh_personality;
+ EhCatchTypeinfo, rust_eh_catch_typeinfo;
}
.all_traits()
.filter(|trait_def_id| {
let viz = self.tcx().visibility(*trait_def_id);
- if let Some(def_id) = self.item_def_id() {
- viz.is_accessible_from(def_id, self.tcx())
- } else {
- viz.is_visible_locally()
- }
+ let def_id = self.item_def_id();
+ viz.is_accessible_from(def_id, self.tcx())
})
.collect();
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{walk_generics, Visitor as _};
-use rustc_hir::lang_items::LangItem;
use rustc_hir::{GenericArg, GenericArgs, OpaqueTyOrigin};
use rustc_middle::middle::stability::AllowUnstable;
use rustc_middle::ty::subst::{self, GenericArgKind, InternalSubsts, SubstsRef};
use rustc_span::edition::Edition;
use rustc_span::lev_distance::find_best_match_for_name;
use rustc_span::symbol::{kw, Ident, Symbol};
-use rustc_span::Span;
+use rustc_span::{sym, Span};
use rustc_target::spec::abi;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::astconv_object_safety_violations;
pub trait AstConv<'tcx> {
fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
- fn item_def_id(&self) -> Option<DefId>;
+ fn item_def_id(&self) -> DefId;
/// Returns predicates in scope of the form `X: Foo<T>`, where `X`
/// is a type parameter `X` with the given id `def_id` and T
item_segment.args(),
item_segment.infer_args,
None,
+ ty::BoundConstness::NotConst,
);
if let Some(b) = item_segment.args().bindings.first() {
Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
generic_args: &'a hir::GenericArgs<'_>,
infer_args: bool,
self_ty: Option<Ty<'tcx>>,
+ constness: ty::BoundConstness,
) -> (SubstsRef<'tcx>, GenericArgCountResult) {
// If the type is parameterized by this region, then replace this
// region with the current anon region binding (in other words,
}
GenericParamDefKind::Const { has_default } => {
let ty = tcx.at(self.span).type_of(param.def_id);
+ if ty.references_error() {
+ return tcx.const_error(ty).into();
+ }
if !infer_args && has_default {
tcx.bound_const_param_default(param.def_id)
.subst(tcx, substs.unwrap())
&mut substs_ctx,
);
+ if let ty::BoundConstness::ConstIfConst = constness
+ && generics.has_self && !tcx.has_attr(def_id, sym::const_trait)
+ {
+ tcx.sess.emit_err(crate::errors::ConstBoundForNonConstTrait { span } );
+ }
+
(substs, arg_count)
}
item_segment.args(),
item_segment.infer_args,
None,
+ ty::BoundConstness::NotConst,
);
if let Some(b) = item_segment.args().bindings.first() {
&self,
trait_ref: &hir::TraitRef<'_>,
self_ty: Ty<'tcx>,
+ constness: ty::BoundConstness,
) -> ty::TraitRef<'tcx> {
self.prohibit_generics(trait_ref.path.segments.split_last().unwrap().1.iter(), |_| {});
self_ty,
trait_ref.path.segments.last().unwrap(),
true,
+ constness,
)
}
args,
infer_args,
Some(self_ty),
+ constness,
);
let tcx = self.tcx();
speculative,
&mut dup_bindings,
binding_span.unwrap_or(binding.span),
+ constness,
);
// Okay to ignore `Err` because of `ErrorGuaranteed` (see above).
}
self_ty: Ty<'tcx>,
trait_segment: &hir::PathSegment<'_>,
is_impl: bool,
+ constness: ty::BoundConstness,
) -> ty::TraitRef<'tcx> {
let (substs, _) = self.create_substs_for_ast_trait_ref(
span,
self_ty,
trait_segment,
is_impl,
+ constness,
);
if let Some(b) = trait_segment.args().bindings.first() {
Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
self_ty: Ty<'tcx>,
trait_segment: &'a hir::PathSegment<'a>,
is_impl: bool,
+ constness: ty::BoundConstness,
) -> (SubstsRef<'tcx>, GenericArgCountResult) {
self.complain_about_internal_fn_trait(span, trait_def_id, trait_segment, is_impl);
trait_segment.args(),
trait_segment.infer_args,
Some(self_ty),
+ constness,
)
}
}
}
- let sized_def_id = tcx.lang_items().require(LangItem::Sized);
+ let sized_def_id = tcx.lang_items().sized_trait();
match (&sized_def_id, unbound) {
- (Ok(sized_def_id), Some(tpb))
+ (Some(sized_def_id), Some(tpb))
if tpb.path.res == Res::Def(DefKind::Trait, *sized_def_id) =>
{
// There was in fact a `?Sized` bound, return without doing anything
// There was no `?Sized` bound; add implicitly sized if `Sized` is available.
}
}
- if sized_def_id.is_err() {
+ if sized_def_id.is_none() {
// No lang item for `Sized`, so we can't add it as a bound.
return;
}
speculative: bool,
dup_bindings: &mut FxHashMap<DefId, Span>,
path_span: Span,
+ constness: ty::BoundConstness,
) -> Result<(), ErrorGuaranteed> {
// Given something like `U: SomeTrait<T = X>`, we want to produce a
// predicate like `<U as SomeTrait>::T = X`. This is somewhat
trait_ref.substs,
);
- debug!(
- "add_predicates_for_ast_type_binding: substs for trait-ref and assoc_item: {:?}",
- substs_trait_ref_and_assoc_item
- );
+ debug!(?substs_trait_ref_and_assoc_item);
ty::ProjectionTy {
item_def_id: assoc_item.def_id,
tcx.collect_constrained_late_bound_regions(&projection_ty);
let late_bound_in_ty =
tcx.collect_referenced_late_bound_regions(&trait_ref.rebind(ty));
- debug!("late_bound_in_trait_ref = {:?}", late_bound_in_trait_ref);
- debug!("late_bound_in_ty = {:?}", late_bound_in_ty);
+ debug!(?late_bound_in_trait_ref);
+ debug!(?late_bound_in_ty);
// FIXME: point at the type params that don't have appropriate lifetimes:
// struct S1<F: for<'a> Fn(&i32, &i32) -> &'a i32>(F);
(_, _) => {
let got = if let Some(_) = term.ty() { "type" } else { "constant" };
let expected = def_kind.descr(assoc_item_def_id);
- tcx.sess
+ let reported = tcx
+ .sess
.struct_span_err(
binding.span,
&format!("expected {expected} bound, found {got}"),
)
.emit();
term = match def_kind {
- hir::def::DefKind::AssocTy => tcx.ty_error().into(),
+ hir::def::DefKind::AssocTy => {
+ tcx.ty_error_with_guaranteed(reported).into()
+ }
hir::def::DefKind::AssocConst => tcx
- .const_error(
+ .const_error_with_guaranteed(
tcx.bound_type_of(assoc_item_def_id)
.subst(tcx, projection_ty.skip_binder().substs),
+ reported,
)
.into(),
_ => unreachable!(),
.map(|&(trait_ref, _, _)| trait_ref.def_id())
.find(|&trait_ref| tcx.is_trait_alias(trait_ref))
.map(|trait_ref| tcx.def_span(trait_ref));
- tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
- return tcx.ty_error();
+ let reported =
+ tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
+ return tcx.ty_error_with_guaranteed(reported);
}
// Check that there are no gross object safety violations;
let object_safety_violations =
astconv_object_safety_violations(tcx, item.trait_ref().def_id());
if !object_safety_violations.is_empty() {
- report_object_safety_error(
+ let reported = report_object_safety_error(
tcx,
span,
item.trait_ref().def_id(),
&object_safety_violations,
)
.emit();
- return tcx.ty_error();
+ return tcx.ty_error_with_guaranteed(reported);
}
}
// Checks that `bounds` contains exactly one element and reports appropriate
// errors otherwise.
+ #[instrument(level = "debug", skip(self, all_candidates, ty_param_name, is_equality), ret)]
fn one_bound_for_assoc_type<I>(
&self,
all_candidates: impl Fn() -> I,
return Err(reported);
}
};
- debug!("one_bound_for_assoc_type: bound = {:?}", bound);
+ debug!(?bound);
if let Some(bound2) = next_cand {
- debug!("one_bound_for_assoc_type: bound2 = {:?}", bound2);
+ debug!(?bound2);
let is_equality = is_equality();
let bounds = IntoIterator::into_iter([bound, bound2]).chain(matching_candidates);
// parameter or `Self`.
// NOTE: When this function starts resolving `Trait::AssocTy` successfully
// it should also start reporting the `BARE_TRAIT_OBJECTS` lint.
+ #[instrument(level = "debug", skip(self, hir_ref_id, span, qself, assoc_segment), fields(assoc_ident=?assoc_segment.ident), ret)]
pub fn associated_path_to_ty(
&self,
hir_ref_id: hir::HirId,
Res::Err
};
- debug!("associated_path_to_ty: {:?}::{}", qself_ty, assoc_ident);
-
// Check if we have an enum variant.
let mut variant_resolution = None;
if let ty::Adt(adt_def, _) = qself_ty.kind() {
}
}
}
+
+ // see if we can satisfy using an inherent associated type
+ for impl_ in tcx.inherent_impls(adt_def.did()) {
+ let assoc_ty = tcx.associated_items(impl_).find_by_name_and_kind(
+ tcx,
+ assoc_ident,
+ ty::AssocKind::Type,
+ *impl_,
+ );
+ if let Some(assoc_ty) = assoc_ty {
+ let ty = tcx.type_of(assoc_ty.def_id);
+ return Ok((ty, DefKind::AssocTy, assoc_ty.def_id));
+ }
+ }
}
// Find the type of the associated item, and the trait where the associated
}
err.emit()
- } else if let Some(reported) = qself_ty.error_reported() {
+ } else if let Err(reported) = qself_ty.error_reported() {
reported
} else {
// Don't print `TyErr` to the user.
item_def_id: DefId,
trait_segment: &hir::PathSegment<'_>,
item_segment: &hir::PathSegment<'_>,
+ constness: ty::BoundConstness,
) -> Ty<'tcx> {
let tcx = self.tcx();
debug!("qpath_to_ty: self.item_def_id()={:?}", def_id);
- let parent_def_id = def_id
- .and_then(|def_id| {
- def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
- })
+ let parent_def_id = def_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
.map(|hir_id| tcx.hir().get_parent_item(hir_id).to_def_id());
debug!("qpath_to_ty: parent_def_id={:?}", parent_def_id);
// If the trait in segment is the same as the trait defining the item,
// use the `<Self as ..>` syntax in the error.
- let is_part_of_self_trait_constraints = def_id == Some(trait_def_id);
+ let is_part_of_self_trait_constraints = def_id == trait_def_id;
let is_part_of_fn_in_self_trait = parent_def_id == Some(trait_def_id);
let type_name = if is_part_of_self_trait_constraints || is_part_of_fn_in_self_trait {
"Type"
};
- self.report_ambiguous_associated_type(
+ let reported = self.report_ambiguous_associated_type(
span,
type_name,
&path_str,
item_segment.ident.name,
);
- return tcx.ty_error();
+ return tcx.ty_error_with_guaranteed(reported)
};
debug!("qpath_to_ty: self_type={:?}", self_ty);
- let trait_ref =
- self.ast_path_to_mono_trait_ref(span, trait_def_id, self_ty, trait_segment, false);
+ let trait_ref = self.ast_path_to_mono_trait_ref(
+ span,
+ trait_def_id,
+ self_ty,
+ trait_segment,
+ false,
+ constness,
+ );
let item_substs = self.create_substs_for_associated_item(
span,
{
err.span_note(impl_.self_ty.span, "not a concrete type");
}
- err.emit();
- tcx.ty_error()
+ tcx.ty_error_with_guaranteed(err.emit())
} else {
self.normalize_ty(span, ty)
}
Res::Def(DefKind::AssocTy, def_id) => {
debug_assert!(path.segments.len() >= 2);
self.prohibit_generics(path.segments[..path.segments.len() - 2].iter(), |_| {});
+ // HACK: until we support `<Type as ~const Trait>`, assume all of them are.
+ let constness = if tcx.has_attr(tcx.parent(def_id), sym::const_trait) {
+ ty::BoundConstness::ConstIfConst
+ } else {
+ ty::BoundConstness::NotConst
+ };
self.qpath_to_ty(
span,
opt_self_ty,
def_id,
&path.segments[path.segments.len() - 2],
path.segments.last().unwrap(),
+ constness,
)
}
Res::PrimTy(prim_ty) => {
}
hir::TyKind::OpaqueDef(item_id, lifetimes, in_trait) => {
let opaque_ty = tcx.hir().item(item_id);
- let def_id = item_id.def_id.to_def_id();
+ let def_id = item_id.owner_id.to_def_id();
match opaque_ty.kind {
hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
&GenericArgs::none(),
true,
None,
+ ty::BoundConstness::NotConst,
);
EarlyBinder(self.normalize_ty(span, tcx.at(span).type_of(def_id)))
.subst(tcx, substs)
}
}
+ #[instrument(level = "debug", skip(self, hir_id, unsafety, abi, decl, generics, hir_ty), ret)]
pub fn ty_of_fn(
&self,
hir_id: hir::HirId,
generics: Option<&hir::Generics<'_>>,
hir_ty: Option<&hir::Ty<'_>>,
) -> ty::PolyFnSig<'tcx> {
- debug!("ty_of_fn");
-
let tcx = self.tcx();
let bound_vars = tcx.late_bound_vars(hir_id);
debug!(?bound_vars);
hir::FnRetTy::DefaultReturn(..) => tcx.mk_unit(),
};
- debug!("ty_of_fn: output_ty={:?}", output_ty);
+ debug!(?output_ty);
let fn_ty = tcx.mk_fn_sig(input_tys.into_iter(), output_ty, decl.c_variadic, unsafety, abi);
let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars);
let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(i), .. }) =
hir.get(hir.get_parent_node(fn_hir_id)) else { bug!("ImplItem should have Impl parent") };
- let trait_ref =
- self.instantiate_mono_trait_ref(i.of_trait.as_ref()?, self.ast_ty_to_ty(i.self_ty));
+ let trait_ref = self.instantiate_mono_trait_ref(
+ i.of_trait.as_ref()?,
+ self.ast_ty_to_ty(i.self_ty),
+ ty::BoundConstness::NotConst,
+ );
let assoc = tcx.associated_items(trait_ref.def_id).find_by_name_and_kind(
tcx,
) {
for br in referenced_regions.difference(&constrained_regions) {
let br_name = match *br {
- ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) | ty::BrEnv => {
+ ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) | ty::BrEnv => {
"an anonymous lifetime".to_string()
}
ty::BrNamed(_, name) => format!("lifetime `{}`", name),
let mut err = generate_err(&br_name);
- if let ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) = *br {
+ if let ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) = *br {
// The only way for an anonymous lifetime to wind up
// in the return type but **also** be unconstrained is
// if it only appears in "associated types" in the
use rustc_attr as attr;
use rustc_errors::{Applicability, ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
-use rustc_hir::def::{DefKind, Res};
+use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
use rustc_hir::{ItemKind, Node, PathSegment};
use rustc_span::symbol::sym;
use rustc_span::{self, Span};
use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedDirective;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::{self, ObligationCtxt};
check_simd(tcx, span, def_id);
}
- check_transparent(tcx, span, def);
+ check_transparent(tcx, def);
check_packed(tcx, span, def);
}
let def = tcx.adt_def(def_id);
let span = tcx.def_span(def_id);
def.destructor(tcx); // force the destructor to be evaluated
- check_transparent(tcx, span, def);
+ check_transparent(tcx, def);
check_union_fields(tcx, span, def_id);
check_packed(tcx, span, def);
}
_ => {
// Fallback case: allow `ManuallyDrop` and things that are `Copy`.
ty.ty_adt_def().is_some_and(|adt_def| adt_def.is_manually_drop())
- || ty.is_copy_modulo_regions(tcx.at(span), param_env)
+ || ty.is_copy_modulo_regions(tcx, param_env)
}
}
}
return;
}
- let substs = InternalSubsts::identity_for_item(tcx, item.def_id.to_def_id());
- let span = tcx.def_span(item.def_id.def_id);
+ let substs = InternalSubsts::identity_for_item(tcx, item.owner_id.to_def_id());
+ let span = tcx.def_span(item.owner_id.def_id);
- check_opaque_for_inheriting_lifetimes(tcx, item.def_id.def_id, span);
- if tcx.type_of(item.def_id.def_id).references_error() {
+ check_opaque_for_inheriting_lifetimes(tcx, item.owner_id.def_id, span);
+ if tcx.type_of(item.owner_id.def_id).references_error() {
return;
}
- if check_opaque_for_cycles(tcx, item.def_id.def_id, substs, span, &origin).is_err() {
+ if check_opaque_for_cycles(tcx, item.owner_id.def_id, substs, span, &origin).is_err() {
return;
}
- check_opaque_meets_bounds(tcx, item.def_id.def_id, substs, span, &origin);
+ check_opaque_meets_bounds(tcx, item.owner_id.def_id, substs, span, &origin);
}
/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
/// in "inheriting lifetimes".
// version.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None);
}
match origin {
// Checked when type checking the function containing them.
fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, id: hir::ItemId) {
debug!(
"check_item_type(it.def_id={:?}, it.name={})",
- id.def_id,
- tcx.def_path_str(id.def_id.to_def_id())
+ id.owner_id,
+ tcx.def_path_str(id.owner_id.to_def_id())
);
let _indenter = indenter();
- match tcx.def_kind(id.def_id) {
+ match tcx.def_kind(id.owner_id) {
DefKind::Static(..) => {
- tcx.ensure().typeck(id.def_id.def_id);
- maybe_check_static_with_link_section(tcx, id.def_id.def_id);
- check_static_inhabited(tcx, id.def_id.def_id);
+ tcx.ensure().typeck(id.owner_id.def_id);
+ maybe_check_static_with_link_section(tcx, id.owner_id.def_id);
+ check_static_inhabited(tcx, id.owner_id.def_id);
}
DefKind::Const => {
- tcx.ensure().typeck(id.def_id.def_id);
+ tcx.ensure().typeck(id.owner_id.def_id);
}
DefKind::Enum => {
- let item = tcx.hir().item(id);
- let hir::ItemKind::Enum(ref enum_definition, _) = item.kind else {
- return;
- };
- check_enum(tcx, &enum_definition.variants, item.def_id.def_id);
+ check_enum(tcx, id.owner_id.def_id);
}
DefKind::Fn => {} // entirely within check_item_body
DefKind::Impl => {
let hir::ItemKind::Impl(ref impl_) = it.kind else {
return;
};
- debug!("ItemKind::Impl {} with id {:?}", it.ident, it.def_id);
- if let Some(impl_trait_ref) = tcx.impl_trait_ref(it.def_id) {
+ debug!("ItemKind::Impl {} with id {:?}", it.ident, it.owner_id);
+ if let Some(impl_trait_ref) = tcx.impl_trait_ref(it.owner_id) {
check_impl_items_against_trait(
tcx,
it.span,
- it.def_id.def_id,
+ it.owner_id.def_id,
impl_trait_ref,
&impl_.items,
);
fn_maybe_err(tcx, item.ident.span, abi);
}
hir::TraitItemKind::Type(.., Some(default)) => {
- let assoc_item = tcx.associated_item(item.def_id);
+ let assoc_item = tcx.associated_item(item.owner_id);
let trait_substs =
- InternalSubsts::identity_for_item(tcx, it.def_id.to_def_id());
+ InternalSubsts::identity_for_item(tcx, it.owner_id.to_def_id());
let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds(
tcx,
assoc_item,
assoc_item,
default.span,
- ty::TraitRef { def_id: it.def_id.to_def_id(), substs: trait_substs },
+ ty::TraitRef { def_id: it.owner_id.to_def_id(), substs: trait_substs },
);
}
_ => {}
}
}
DefKind::Struct => {
- check_struct(tcx, id.def_id.def_id);
+ check_struct(tcx, id.owner_id.def_id);
}
DefKind::Union => {
- check_union(tcx, id.def_id.def_id);
+ check_union(tcx, id.owner_id.def_id);
}
DefKind::OpaqueTy => {
check_opaque(tcx, id);
}
DefKind::ImplTraitPlaceholder => {
- let parent = tcx.impl_trait_in_trait_parent(id.def_id.to_def_id());
+ let parent = tcx.impl_trait_in_trait_parent(id.owner_id.to_def_id());
// Only check the validity of this opaque type if the function has a default body
if let hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(_)),
}
}
DefKind::TyAlias => {
- let pty_ty = tcx.type_of(id.def_id);
- let generics = tcx.generics_of(id.def_id);
+ let pty_ty = tcx.type_of(id.owner_id);
+ let generics = tcx.generics_of(id.owner_id);
check_type_params_are_used(tcx, &generics, pty_ty);
}
DefKind::ForeignMod => {
}
} else {
for item in items {
- let def_id = item.id.def_id.def_id;
+ let def_id = item.id.owner_id.def_id;
let generics = tcx.generics_of(def_id);
let own_counts = generics.own_counts();
if generics.params.len() - own_counts.lifetimes != 0 {
pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
// an error would be reported if this fails.
- let _ = traits::OnUnimplementedDirective::of_item(tcx, item.def_id.to_def_id());
+ let _ = OnUnimplementedDirective::of_item(tcx, item.owner_id.to_def_id());
}
pub(super) fn check_specialization_validity<'tcx>(
let trait_def = tcx.trait_def(impl_trait_ref.def_id);
for impl_item in impl_item_refs {
- let ty_impl_item = tcx.associated_item(impl_item.id.def_id);
+ let ty_impl_item = tcx.associated_item(impl_item.id.owner_id);
let ty_trait_item = if let Some(trait_item_id) = ty_impl_item.trait_item_def_id {
tcx.associated_item(trait_item_id)
} else {
match impl_item_full.kind {
hir::ImplItemKind::Const(..) => {
let _ = tcx.compare_assoc_const_impl_item_with_trait_item((
- impl_item.id.def_id.def_id,
+ impl_item.id.owner_id.def_id,
ty_impl_item.trait_item_def_id.unwrap(),
));
}
None
}
-pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtDef<'tcx>) {
+pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) {
if !adt.repr().transparent() {
return;
}
feature_err(
&tcx.sess.parse_sess,
sym::transparent_unions,
- sp,
+ tcx.def_span(adt.did()),
"transparent unions are unstable",
)
.emit();
}
if adt.variants().len() != 1 {
- bad_variant_count(tcx, adt, sp, adt.did());
+ bad_variant_count(tcx, adt, tcx.def_span(adt.did()), adt.did());
if adt.variants().is_empty() {
// Don't bother checking the fields. No variants (and thus no fields) exist.
return;
.filter_map(|(span, zst, _align1, _non_exhaustive)| if !zst { Some(span) } else { None });
let non_zst_count = non_zst_fields.clone().count();
if non_zst_count >= 2 {
- bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp);
+ bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, tcx.def_span(adt.did()));
}
let incompatible_zst_fields =
field_infos.clone().filter(|(_, _, _, opt)| opt.is_some()).count();
}
#[allow(trivial_numeric_casts)]
-fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, vs: &'tcx [hir::Variant<'tcx>], def_id: LocalDefId) {
+fn check_enum<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
let def = tcx.adt_def(def_id);
- let sp = tcx.def_span(def_id);
def.destructor(tcx); // force the destructor to be evaluated
- if vs.is_empty() {
+ if def.variants().is_empty() {
if let Some(attr) = tcx.get_attrs(def_id.to_def_id(), sym::repr).next() {
struct_span_err!(
tcx.sess,
E0084,
"unsupported representation for zero-variant enum"
)
- .span_label(sp, "zero-variant enum")
+ .span_label(tcx.def_span(def_id), "zero-variant enum")
.emit();
}
}
feature_err(
&tcx.sess.parse_sess,
sym::repr128,
- sp,
+ tcx.def_span(def_id),
"repr with 128-bit type is unstable",
)
.emit();
}
}
- for v in vs {
- if let Some(ref e) = v.disr_expr {
- tcx.ensure().typeck(tcx.hir().local_def_id(e.hir_id));
+ for v in def.variants() {
+ if let ty::VariantDiscr::Explicit(discr_def_id) = v.discr {
+ tcx.ensure().typeck(discr_def_id.expect_local());
}
}
- if tcx.adt_def(def_id).repr().int.is_none() {
- let is_unit = |var: &hir::Variant<'_>| matches!(var.data, hir::VariantData::Unit(..));
+ if def.repr().int.is_none() {
+ let is_unit = |var: &ty::VariantDef| matches!(var.ctor_kind, CtorKind::Const);
+ let has_disr = |var: &ty::VariantDef| matches!(var.discr, ty::VariantDiscr::Explicit(_));
- let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some();
- let has_non_units = vs.iter().any(|var| !is_unit(var));
- let disr_units = vs.iter().any(|var| is_unit(&var) && has_disr(&var));
- let disr_non_unit = vs.iter().any(|var| !is_unit(&var) && has_disr(&var));
+ let has_non_units = def.variants().iter().any(|var| !is_unit(var));
+ let disr_units = def.variants().iter().any(|var| is_unit(&var) && has_disr(&var));
+ let disr_non_unit = def.variants().iter().any(|var| !is_unit(&var) && has_disr(&var));
if disr_non_unit || (disr_units && has_non_units) {
- let mut err =
- struct_span_err!(tcx.sess, sp, E0732, "`#[repr(inttype)]` must be specified");
+ let mut err = struct_span_err!(
+ tcx.sess,
+ tcx.def_span(def_id),
+ E0732,
+ "`#[repr(inttype)]` must be specified"
+ );
err.emit();
}
}
- detect_discriminant_duplicate(tcx, def.discriminants(tcx).collect(), vs, sp);
-
- check_transparent(tcx, sp, def);
+ detect_discriminant_duplicate(tcx, def);
+ check_transparent(tcx, def);
}
/// Part of enum check. Given the discriminants of an enum, errors if two or more discriminants are equal
-fn detect_discriminant_duplicate<'tcx>(
- tcx: TyCtxt<'tcx>,
- mut discrs: Vec<(VariantIdx, Discr<'tcx>)>,
- vs: &'tcx [hir::Variant<'tcx>],
- self_span: Span,
-) {
+fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) {
// Helper closure to reduce duplicate code. This gets called everytime we detect a duplicate.
// Here `idx` refers to the order of which the discriminant appears, and its index in `vs`
- let report = |dis: Discr<'tcx>, idx: usize, err: &mut Diagnostic| {
- let var = &vs[idx]; // HIR for the duplicate discriminant
- let (span, display_discr) = match var.disr_expr {
- Some(ref expr) => {
+ let report = |dis: Discr<'tcx>, idx, err: &mut Diagnostic| {
+ let var = adt.variant(idx); // HIR for the duplicate discriminant
+ let (span, display_discr) = match var.discr {
+ ty::VariantDiscr::Explicit(discr_def_id) => {
// In the case the discriminant is both a duplicate and overflowed, let the user know
- if let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind
+ if let hir::Node::AnonConst(expr) = tcx.hir().get_by_def_id(discr_def_id.expect_local())
+ && let hir::ExprKind::Lit(lit) = &tcx.hir().body(expr.body).value.kind
&& let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node
&& *lit_value != dis.val
{
- (tcx.hir().span(expr.hir_id), format!("`{dis}` (overflowed from `{lit_value}`)"))
- // Otherwise, format the value as-is
+ (tcx.def_span(discr_def_id), format!("`{dis}` (overflowed from `{lit_value}`)"))
} else {
- (tcx.hir().span(expr.hir_id), format!("`{dis}`"))
+ // Otherwise, format the value as-is
+ (tcx.def_span(discr_def_id), format!("`{dis}`"))
}
}
- None => {
+ // This should not happen.
+ ty::VariantDiscr::Relative(0) => (tcx.def_span(var.def_id), format!("`{dis}`")),
+ ty::VariantDiscr::Relative(distance_to_explicit) => {
// At this point we know this discriminant is a duplicate, and was not explicitly
// assigned by the user. Here we iterate backwards to fetch the HIR for the last
// explicitly assigned discriminant, and letting the user know that this was the
// increment startpoint, and how many steps from there leading to the duplicate
- if let Some((n, hir::Variant { span, ident, .. })) =
- vs[..idx].iter().rev().enumerate().find(|v| v.1.disr_expr.is_some())
+ if let Some(explicit_idx) =
+ idx.as_u32().checked_sub(distance_to_explicit).map(VariantIdx::from_u32)
{
- let ve_ident = var.ident;
- let n = n + 1;
- let sp = if n > 1 { "variants" } else { "variant" };
+ let explicit_variant = adt.variant(explicit_idx);
+ let ve_ident = var.name;
+ let ex_ident = explicit_variant.name;
+ let sp = if distance_to_explicit > 1 { "variants" } else { "variant" };
err.span_label(
- *span,
- format!("discriminant for `{ve_ident}` incremented from this startpoint (`{ident}` + {n} {sp} later => `{ve_ident}` = {dis})"),
+ tcx.def_span(explicit_variant.def_id),
+ format!(
+ "discriminant for `{ve_ident}` incremented from this startpoint \
+ (`{ex_ident}` + {distance_to_explicit} {sp} later \
+ => `{ve_ident}` = {dis})"
+ ),
);
}
- (vs[idx].span, format!("`{dis}`"))
+ (tcx.def_span(var.def_id), format!("`{dis}`"))
}
};
err.span_label(span, format!("{display_discr} assigned here"));
};
+ let mut discrs = adt.discriminants(tcx).collect::<Vec<_>>();
+
// Here we loop through the discriminants, comparing each discriminant to another.
// When a duplicate is detected, we instantiate an error and point to both
// initial and duplicate value. The duplicate discriminant is then discarded by swapping
// style as we are mutating `discrs` on the fly).
let mut i = 0;
while i < discrs.len() {
- let hir_var_i_idx = discrs[i].0.index();
+ let var_i_idx = discrs[i].0;
let mut error: Option<DiagnosticBuilder<'_, _>> = None;
let mut o = i + 1;
while o < discrs.len() {
- let hir_var_o_idx = discrs[o].0.index();
+ let var_o_idx = discrs[o].0;
if discrs[i].1.val == discrs[o].1.val {
let err = error.get_or_insert_with(|| {
let mut ret = struct_span_err!(
tcx.sess,
- self_span,
+ tcx.def_span(adt.did()),
E0081,
"discriminant value `{}` assigned more than once",
discrs[i].1,
);
- report(discrs[i].1, hir_var_i_idx, &mut ret);
+ report(discrs[i].1, var_i_idx, &mut ret);
ret
});
- report(discrs[o].1, hir_var_o_idx, err);
+ report(discrs[o].1, var_o_idx, err);
// Safe to unwrap here, as we wouldn't reach this point if `discrs` was empty
discrs[o] = *discrs.last().unwrap();
// type would be more appropriate. In other places we have a `Vec<Span>`
// corresponding to their `Vec<Predicate>`, but we don't have that here.
// Fixing this would improve the output of test `issue-83765.rs`.
- let mut result = infcx
- .at(&cause, param_env)
- .sup(trait_fty, impl_fty)
- .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok));
+ let mut result = ocx.sup(&cause, param_env, trait_fty, impl_fty);
// HACK(RPITIT): #101614. When we are trying to infer the hidden types for
// RPITITs, we need to equate the output tys instead of just subtyping. If
// us to infer `_#1t = #'_#2r str`, where `'_#2r` is unconstrained, which gets
// fixed up to `ReEmpty`, and which is certainly not what we want.
if trait_fty.has_infer_types() {
- result = result.and_then(|()| {
- infcx
- .at(&cause, param_env)
- .eq(trait_sig.output(), impl_sig.output())
- .map(|infer_ok| ocx.register_infer_ok_obligations(infer_ok))
- });
+ result =
+ result.and_then(|()| ocx.eq(&cause, param_env, trait_sig.output(), impl_sig.output()));
}
if let Err(terr) = result {
// version.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
return Err(reported);
}
// RPITs.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
return Err(reported);
}
let num_trait_substs = trait_to_impl_substs.len();
let num_impl_substs = tcx.generics_of(impl_m.container_id(tcx)).params.len();
let ty = tcx.fold_regions(ty, |region, _| {
- let ty::ReFree(_) = region.kind() else { return region; };
+ let (ty::ReFree(_) | ty::ReEarlyBound(_)) = region.kind() else { return region; };
let Some(ty::ReEarlyBound(e)) = map.get(®ion.into()).map(|r| r.expect_region().kind())
else {
tcx
collected_tys.insert(def_id, ty);
}
Err(err) => {
- tcx.sess.delay_span_bug(
+ let reported = tcx.sess.delay_span_bug(
return_span,
format!("could not fully resolve: {ty} => {err:?}"),
);
- collected_tys.insert(def_id, tcx.ty_error());
+ collected_tys.insert(def_id, tcx.ty_error_with_guaranteed(reported));
}
}
}
debug!("compare_const_impl: trait_ty={:?}", trait_ty);
- let err = infcx
- .at(&cause, param_env)
- .sup(trait_ty, impl_ty)
- .map(|ok| ocx.register_infer_ok_obligations(ok));
+ let err = ocx.sup(&cause, param_env, trait_ty, impl_ty);
if let Err(terr) = err {
debug!(
// version.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- return Err(infcx.err_ctxt().report_fulfillment_errors(&errors, None, false));
+ return Err(infcx.err_ctxt().report_fulfillment_errors(&errors, None));
}
// FIXME return `ErrorReported` if region obligations error?
// version.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
return Err(reported);
}
GenericParamDefKind::Const { .. } => {
let bound_var = ty::BoundVariableKind::Const;
bound_vars.push(bound_var);
- tcx.mk_const(ty::ConstS {
- ty: tcx.type_of(param.def_id),
- kind: ty::ConstKind::Bound(
- ty::INNERMOST,
- ty::BoundVar::from_usize(bound_vars.len() - 1),
- ),
- })
+ tcx.mk_const(
+ ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_usize(bound_vars.len() - 1)),
+ tcx.type_of(param.def_id),
+ )
.into()
}
});
// version.
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
return Err(reported);
}
) {
let (own_counts, span) = match &it.kind {
hir::ForeignItemKind::Fn(.., generics) => {
- let own_counts = tcx.generics_of(it.def_id.to_def_id()).own_counts();
+ let own_counts = tcx.generics_of(it.owner_id.to_def_id()).own_counts();
(own_counts, generics.span)
}
_ => {
{
let fty = tcx.mk_fn_ptr(sig);
let cause = ObligationCause::new(it.span, it.hir_id(), ObligationCauseCode::IntrinsicType);
- require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(it.def_id)), fty);
+ require_same_types(tcx, &cause, tcx.mk_fn_ptr(tcx.fn_sig(it.owner_id)), fty);
}
}
/// and in `library/core/src/intrinsics.rs`.
pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n)));
- let intrinsic_id = it.def_id.to_def_id();
+ let intrinsic_id = it.owner_id.to_def_id();
let intrinsic_name = tcx.item_name(intrinsic_id);
let name_str = intrinsic_name.as_str();
let bound_vars = tcx.mk_bound_variable_kinds(
- [ty::BoundVariableKind::Region(ty::BrAnon(0)), ty::BoundVariableKind::Region(ty::BrEnv)]
- .iter()
- .copied(),
+ [
+ ty::BoundVariableKind::Region(ty::BrAnon(0, None)),
+ ty::BoundVariableKind::Region(ty::BrEnv),
+ ]
+ .iter()
+ .copied(),
);
let mk_va_list_ty = |mutbl| {
tcx.lang_items().va_list().map(|did| {
let region = tcx.mk_region(ty::ReLateBound(
ty::INNERMOST,
- ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) },
+ ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) },
));
let env_region = tcx.mk_region(ty::ReLateBound(
ty::INNERMOST,
);
let discriminant_def_id = assoc_items[0];
- let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) };
+ let br =
+ ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) };
(
1,
vec![
sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
sym::raw_eq => {
- let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0) };
+ let br =
+ ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind: ty::BrAnon(0, None) };
let param_ty =
tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)), param(0));
(1, vec![param_ty; 2], tcx.types.bool)
fn is_thin_ptr_ty(&self, ty: Ty<'tcx>) -> bool {
// Type still may have region variables, but `Sized` does not depend
// on those, so just erase them before querying.
- if ty.is_sized(self.tcx.at(DUMMY_SP), self.param_env) {
+ if ty.is_sized(self.tcx, self.param_env) {
return true;
}
if let ty::Foreign(..) = ty.kind() {
// Check that the type implements Copy. The only case where this can
// possibly fail is for SIMD types which don't #[derive(Copy)].
- if !ty.is_copy_modulo_regions(self.tcx.at(expr.span), self.param_env) {
+ if !ty.is_copy_modulo_regions(self.tcx, self.param_env) {
let msg = "arguments for inline assembly must be copyable";
let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
err.note(&format!("`{ty}` does not implement the Copy trait"));
use rustc_session::parse::feature_err;
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
+use rustc_target::spec::abi::Abi;
use rustc_trait_selection::autoderef::Autoderef;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
f(&mut wfcx);
let errors = wfcx.select_all_or_error();
if !errors.is_empty() {
- infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None);
return;
}
/// the types first.
#[instrument(skip(tcx), level = "debug")]
fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
- let def_id = item.def_id.def_id;
+ let def_id = item.owner_id.def_id;
debug!(
- ?item.def_id,
+ ?item.owner_id,
item.name = ? tcx.def_path_str(def_id.to_def_id())
);
hir::ItemKind::Const(ty, ..) => {
check_item_type(tcx, def_id, ty.span, false);
}
- hir::ItemKind::Struct(ref struct_def, ref ast_generics) => {
- check_type_defn(tcx, item, false, |wfcx| vec![wfcx.non_enum_variant(struct_def)]);
-
+ hir::ItemKind::Struct(_, ref ast_generics) => {
+ check_type_defn(tcx, item, false);
check_variances_for_type_defn(tcx, item, ast_generics);
}
- hir::ItemKind::Union(ref struct_def, ref ast_generics) => {
- check_type_defn(tcx, item, true, |wfcx| vec![wfcx.non_enum_variant(struct_def)]);
-
+ hir::ItemKind::Union(_, ref ast_generics) => {
+ check_type_defn(tcx, item, true);
check_variances_for_type_defn(tcx, item, ast_generics);
}
- hir::ItemKind::Enum(ref enum_def, ref ast_generics) => {
- check_type_defn(tcx, item, true, |wfcx| wfcx.enum_variants(enum_def));
-
+ hir::ItemKind::Enum(_, ref ast_generics) => {
+ check_type_defn(tcx, item, true);
check_variances_for_type_defn(tcx, item, ast_generics);
}
hir::ItemKind::Trait(..) => {
}
fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) {
- let def_id = item.def_id.def_id;
+ let def_id = item.owner_id.def_id;
debug!(
- ?item.def_id,
+ ?item.owner_id,
item.name = ? tcx.def_path_str(def_id.to_def_id())
);
}
fn check_trait_item(tcx: TyCtxt<'_>, trait_item: &hir::TraitItem<'_>) {
- let def_id = trait_item.def_id.def_id;
+ let def_id = trait_item.owner_id.def_id;
let (method_sig, span) = match trait_item.kind {
hir::TraitItemKind::Fn(ref sig, _) => (Some(sig), trait_item.span),
let encl_trait_def_id = tcx.local_parent(def_id);
let encl_trait = tcx.hir().expect_item(encl_trait_def_id);
- let encl_trait_def_id = encl_trait.def_id.to_def_id();
+ let encl_trait_def_id = encl_trait.owner_id.to_def_id();
let fn_lang_item_name = if Some(encl_trait_def_id) == tcx.lang_items().fn_trait() {
Some("fn")
} else if Some(encl_trait_def_id) == tcx.lang_items().fn_mut_trait() {
loop {
let mut should_continue = false;
for gat_item in associated_items {
- let gat_def_id = gat_item.id.def_id;
+ let gat_def_id = gat_item.id.owner_id;
let gat_item = tcx.associated_item(gat_def_id);
// If this item is not an assoc ty, or has no substs, then it's not a GAT
if gat_item.kind != ty::AssocKind::Type {
// constrains the GAT with individually.
let mut new_required_bounds: Option<FxHashSet<ty::Predicate<'_>>> = None;
for item in associated_items {
- let item_def_id = item.id.def_id;
+ let item_def_id = item.id.owner_id;
// Skip our own GAT, since it does not constrain itself at all.
if item_def_id == gat_def_id {
continue;
add_constraints(&infcx, region_bound_pairs);
+ infcx.process_registered_region_obligations(
+ outlives_environment.region_bound_pairs(),
+ param_env,
+ );
let errors = infcx.resolve_regions(&outlives_environment);
debug!(?errors, "errors");
let (trait_name, trait_def_id) =
match tcx.hir().get_by_def_id(tcx.hir().get_parent_item(item.hir_id()).def_id) {
hir::Node::Item(item) => match item.kind {
- hir::ItemKind::Trait(..) => (item.ident, item.def_id),
+ hir::ItemKind::Trait(..) => (item.ident, item.owner_id),
_ => return,
},
_ => return,
_ => (None, impl_item.span),
};
- check_associated_item(tcx, impl_item.def_id.def_id, span, method_sig);
+ check_associated_item(tcx, impl_item.owner_id.def_id, span, method_sig);
}
fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
}
/// In a type definition, we check that to ensure that the types of the fields are well-formed.
-fn check_type_defn<'tcx, F>(
- tcx: TyCtxt<'tcx>,
- item: &hir::Item<'tcx>,
- all_sized: bool,
- mut lookup_fields: F,
-) where
- F: FnMut(&WfCheckingCtxt<'_, 'tcx>) -> Vec<AdtVariant<'tcx>>,
-{
- let _ = tcx.representability(item.def_id.def_id);
+fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: bool) {
+ let _ = tcx.representability(item.owner_id.def_id);
+ let adt_def = tcx.adt_def(item.owner_id);
- enter_wf_checking_ctxt(tcx, item.span, item.def_id.def_id, |wfcx| {
- let variants = lookup_fields(wfcx);
- let packed = tcx.adt_def(item.def_id).repr().packed();
+ enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| {
+ let variants = adt_def.variants();
+ let packed = adt_def.repr().packed();
- for variant in &variants {
+ for variant in variants.iter() {
// All field types must be well-formed.
for field in &variant.fields {
+ let field_id = field.did.expect_local();
+ let hir::Node::Field(hir::FieldDef { ty: hir_ty, .. }) = tcx.hir().get_by_def_id(field_id)
+ else { bug!() };
+ let ty = wfcx.normalize(hir_ty.span, None, tcx.type_of(field.did));
wfcx.register_wf_obligation(
- field.span,
- Some(WellFormedLoc::Ty(field.def_id)),
- field.ty.into(),
+ hir_ty.span,
+ Some(WellFormedLoc::Ty(field_id)),
+ ty.into(),
)
}
// intermediate types must be sized.
let needs_drop_copy = || {
packed && {
- let ty = variant.fields.last().unwrap().ty;
+ let ty = tcx.type_of(variant.fields.last().unwrap().did);
let ty = tcx.erase_regions(ty);
if ty.needs_infer() {
tcx.sess
// Just treat unresolved type expression as if it needs drop.
true
} else {
- ty.needs_drop(tcx, tcx.param_env(item.def_id))
+ ty.needs_drop(tcx, tcx.param_env(item.owner_id))
}
}
};
variant.fields[..variant.fields.len() - unsized_len].iter().enumerate()
{
let last = idx == variant.fields.len() - 1;
+ let field_id = field.did.expect_local();
+ let hir::Node::Field(hir::FieldDef { ty: hir_ty, .. }) = tcx.hir().get_by_def_id(field_id)
+ else { bug!() };
+ let ty = wfcx.normalize(hir_ty.span, None, tcx.type_of(field.did));
wfcx.register_bound(
traits::ObligationCause::new(
- field.span,
+ hir_ty.span,
wfcx.body_id,
traits::FieldSized {
adt_kind: match item_adt_kind(&item.kind) {
Some(i) => i,
None => bug!(),
},
- span: field.span,
+ span: hir_ty.span,
last,
},
),
wfcx.param_env,
- field.ty,
+ ty,
tcx.require_lang_item(LangItem::Sized, None),
);
}
// Explicit `enum` discriminant values must const-evaluate successfully.
- if let Some(discr_def_id) = variant.explicit_discr {
+ if let ty::VariantDiscr::Explicit(discr_def_id) = variant.discr {
let cause = traits::ObligationCause::new(
tcx.def_span(discr_def_id),
wfcx.body_id,
cause,
wfcx.param_env,
ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(
- ty::Const::from_anon_const(tcx, discr_def_id),
+ ty::Const::from_anon_const(tcx, discr_def_id.expect_local()),
))
.to_predicate(tcx),
));
}
}
- check_where_clauses(wfcx, item.span, item.def_id.def_id);
+ check_where_clauses(wfcx, item.span, item.owner_id.def_id);
});
}
#[instrument(skip(tcx, item))]
fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) {
- debug!(?item.def_id);
+ debug!(?item.owner_id);
- let def_id = item.def_id.def_id;
+ let def_id = item.owner_id.def_id;
let trait_def = tcx.trait_def(def_id);
if trait_def.is_marker
|| matches!(trait_def.specialization_kind, TraitSpecializationKind::Marker)
ast_trait_ref: &Option<hir::TraitRef<'_>>,
constness: hir::Constness,
) {
- enter_wf_checking_ctxt(tcx, item.span, item.def_id.def_id, |wfcx| {
+ enter_wf_checking_ctxt(tcx, item.span, item.owner_id.def_id, |wfcx| {
match *ast_trait_ref {
Some(ref ast_trait_ref) => {
// `#[rustc_reservation_impl]` impls are not real impls and
// therefore don't need to be WF (the trait's `Self: Trait` predicate
// won't hold).
- let trait_ref = tcx.impl_trait_ref(item.def_id).unwrap();
+ let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap();
let trait_ref = wfcx.normalize(ast_trait_ref.path.span, None, trait_ref);
let trait_pred = ty::TraitPredicate {
trait_ref,
wfcx.register_obligations(obligations);
}
None => {
- let self_ty = tcx.type_of(item.def_id);
+ let self_ty = tcx.type_of(item.owner_id);
let self_ty = wfcx.normalize(
item.span,
Some(WellFormedLoc::Ty(item.hir_id().expect_owner().def_id)),
}
}
- check_where_clauses(wfcx, item.span, item.def_id.def_id);
+ check_where_clauses(wfcx, item.span, item.owner_id.def_id);
});
}
sig.output(),
hir_decl.output.span(),
);
+
+ if sig.abi == Abi::RustCall {
+ let span = tcx.def_span(def_id);
+ let has_implicit_self = hir_decl.implicit_self != hir::ImplicitSelfKind::None;
+ let mut inputs = sig.inputs().iter().skip(if has_implicit_self { 1 } else { 0 });
+ // Check that the argument is a tuple
+ if let Some(ty) = inputs.next() {
+ wfcx.register_bound(
+ ObligationCause::new(span, wfcx.body_id, ObligationCauseCode::RustCall),
+ wfcx.param_env,
+ *ty,
+ tcx.require_lang_item(hir::LangItem::Tuple, Some(span)),
+ );
+ } else {
+ tcx.sess.span_err(
+ hir_decl.inputs.last().map_or(span, |input| input.span),
+ "functions with the \"rust-call\" ABI must take a single non-self tuple argument",
+ );
+ }
+ // No more inputs other than the `self` type and the tuple type
+ if inputs.next().is_some() {
+ tcx.sess.span_err(
+ hir_decl.inputs.last().map_or(span, |input| input.span),
+ "functions with the \"rust-call\" ABI must take a single non-self tuple argument",
+ );
+ }
+ }
}
/// Basically `check_associated_type_bounds`, but separated for now and should be
// `self: Self` is always valid.
if can_eq_self(receiver_ty) {
- if let Err(err) = wfcx.equate_types(&cause, wfcx.param_env, self_ty, receiver_ty) {
+ if let Err(err) = wfcx.eq(&cause, wfcx.param_env, self_ty, receiver_ty) {
infcx.err_ctxt().report_mismatched_types(&cause, self_ty, receiver_ty, err).emit();
}
return true;
if can_eq_self(potential_self_ty) {
wfcx.register_obligations(autoderef.into_obligations());
- if let Err(err) =
- wfcx.equate_types(&cause, wfcx.param_env, self_ty, potential_self_ty)
- {
+ if let Err(err) = wfcx.eq(&cause, wfcx.param_env, self_ty, potential_self_ty) {
infcx
.err_ctxt()
.report_mismatched_types(&cause, self_ty, potential_self_ty, err)
item: &hir::Item<'tcx>,
hir_generics: &hir::Generics<'_>,
) {
- let ty = tcx.type_of(item.def_id);
+ let ty = tcx.type_of(item.owner_id);
if tcx.has_error_field(ty) {
return;
}
- let ty_predicates = tcx.predicates_of(item.def_id);
+ let ty_predicates = tcx.predicates_of(item.owner_id);
assert_eq!(ty_predicates.parent, None);
- let variances = tcx.variances_of(item.def_id);
+ let variances = tcx.variances_of(item.owner_id);
let mut constrained_parameters: FxHashSet<_> = variances
.iter()
// Lazily calculated because it is only needed in case of an error.
let explicitly_bounded_params = LazyCell::new(|| {
- let icx = crate::collect::ItemCtxt::new(tcx, item.def_id.to_def_id());
+ let icx = crate::collect::ItemCtxt::new(tcx, item.owner_id.to_def_id());
hir_generics
.predicates
.iter()
fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalDefId) {
let items = tcx.hir_module_items(module);
- items.par_items(|item| tcx.ensure().check_well_formed(item.def_id));
- items.par_impl_items(|item| tcx.ensure().check_well_formed(item.def_id));
- items.par_trait_items(|item| tcx.ensure().check_well_formed(item.def_id));
- items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.def_id));
-}
-
-///////////////////////////////////////////////////////////////////////////
-// ADT
-
-// FIXME(eddyb) replace this with getting fields/discriminants through `ty::AdtDef`.
-struct AdtVariant<'tcx> {
- /// Types of fields in the variant, that must be well-formed.
- fields: Vec<AdtField<'tcx>>,
-
- /// Explicit discriminant of this variant (e.g. `A = 123`),
- /// that must evaluate to a constant value.
- explicit_discr: Option<LocalDefId>,
-}
-
-struct AdtField<'tcx> {
- ty: Ty<'tcx>,
- def_id: LocalDefId,
- span: Span,
-}
-
-impl<'a, 'tcx> WfCheckingCtxt<'a, 'tcx> {
- // FIXME(eddyb) replace this with getting fields through `ty::AdtDef`.
- fn non_enum_variant(&self, struct_def: &hir::VariantData<'_>) -> AdtVariant<'tcx> {
- let fields = struct_def
- .fields()
- .iter()
- .map(|field| {
- let def_id = self.tcx().hir().local_def_id(field.hir_id);
- let field_ty = self.tcx().type_of(def_id);
- let field_ty = self.normalize(field.ty.span, None, field_ty);
- debug!("non_enum_variant: type of field {:?} is {:?}", field, field_ty);
- AdtField { ty: field_ty, span: field.ty.span, def_id }
- })
- .collect();
- AdtVariant { fields, explicit_discr: None }
- }
-
- fn enum_variants(&self, enum_def: &hir::EnumDef<'_>) -> Vec<AdtVariant<'tcx>> {
- enum_def
- .variants
- .iter()
- .map(|variant| AdtVariant {
- fields: self.non_enum_variant(&variant.data).fields,
- explicit_discr: variant
- .disr_expr
- .map(|explicit_discr| self.tcx().hir().local_def_id(explicit_discr.hir_id)),
- })
- .collect()
- }
+ items.par_items(|item| tcx.ensure().check_well_formed(item.owner_id));
+ items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id));
+ items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id));
+ items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id));
}
fn error_392(
use crate::errors::{ExternCrateNotIdiomatic, UnusedExternCrate};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::unord::UnordSet;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_span::{Span, Symbol};
pub fn check_crate(tcx: TyCtxt<'_>) {
- let mut used_trait_imports: FxHashSet<LocalDefId> = FxHashSet::default();
+ let mut used_trait_imports: UnordSet<LocalDefId> = Default::default();
for item_def_id in tcx.hir().body_owners() {
let imports = tcx.used_trait_imports(item_def_id);
debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports);
- used_trait_imports.extend(imports.iter());
+ used_trait_imports.extend(imports.items().copied());
}
for &id in tcx.maybe_unused_trait_imports(()) {
let mut crates_to_lint = vec![];
for id in tcx.hir().items() {
- if matches!(tcx.def_kind(id.def_id), DefKind::ExternCrate) {
+ if matches!(tcx.def_kind(id.owner_id), DefKind::ExternCrate) {
let item = tcx.hir().item(id);
if let hir::ItemKind::ExternCrate(orig_name) = item.kind {
crates_to_lint.push(ExternCrateToLint {
- def_id: item.def_id.to_def_id(),
+ def_id: item.owner_id.to_def_id(),
span: item.span,
orig_name,
warn_if_unused: !item.ident.as_str().starts_with('_'),
}),
);
if !errors.is_empty() {
- infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None);
}
// Finally, resolve all regions.
predicate_for_trait_def(tcx, param_env, cause, trait_def_id, 0, source, &[target.into()]);
let errors = traits::fully_solve_obligation(&infcx, predicate);
if !errors.is_empty() {
- infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None);
}
// Finally, resolve all regions.
impl<'tcx> InherentCollect<'tcx> {
fn check_def_id(&mut self, item: &hir::Item<'_>, self_ty: Ty<'tcx>, def_id: DefId) {
- let impl_def_id = item.def_id;
+ let impl_def_id = item.owner_id;
if let Some(def_id) = def_id.as_local() {
// Add the implementation to the mapping from implementation to base
// type def ID, if there is a base type for this implementation and
for impl_item in items {
if !self
.tcx
- .has_attr(impl_item.id.def_id.to_def_id(), sym::rustc_allow_incoherent_impl)
+ .has_attr(impl_item.id.owner_id.to_def_id(), sym::rustc_allow_incoherent_impl)
{
struct_span_err!(
self.tcx.sess,
for item in items {
if !self
.tcx
- .has_attr(item.id.def_id.to_def_id(), sym::rustc_allow_incoherent_impl)
+ .has_attr(item.id.owner_id.to_def_id(), sym::rustc_allow_incoherent_impl)
{
struct_span_err!(
self.tcx.sess,
}
fn check_item(&mut self, id: hir::ItemId) {
- if !matches!(self.tcx.def_kind(id.def_id), DefKind::Impl) {
+ if !matches!(self.tcx.def_kind(id.owner_id), DefKind::Impl) {
return;
}
return;
};
- let self_ty = self.tcx.type_of(item.def_id);
+ let self_ty = self.tcx.type_of(item.owner_id);
match *self_ty.kind() {
ty::Adt(def, _) => {
self.check_def_id(item, self_ty, def.did());
| ty::Never
| ty::FnPtr(_)
| ty::Tuple(..) => {
- self.check_primitive_impl(item.def_id.def_id, self_ty, items, ty.span)
+ self.check_primitive_impl(item.owner_id.def_id, self_ty, items, ty.span)
}
ty::Projection(..) | ty::Opaque(..) | ty::Param(_) => {
let mut err = struct_span_err!(
| ty::Bound(..)
| ty::Placeholder(_)
| ty::Infer(_) => {
- bug!("unexpected impl self type of impl: {:?} {:?}", item.def_id, self_ty);
+ bug!("unexpected impl self type of impl: {:?} {:?}", item.owner_id, self_ty);
}
ty::Error(_) => {}
}
}
fn check_item(&mut self, id: hir::ItemId) {
- let def_kind = self.tcx.def_kind(id.def_id);
+ let def_kind = self.tcx.def_kind(id.owner_id);
if !matches!(def_kind, DefKind::Enum | DefKind::Struct | DefKind::Trait | DefKind::Union) {
return;
}
- let impls = self.tcx.inherent_impls(id.def_id);
+ let impls = self.tcx.inherent_impls(id.owner_id);
- let overlap_mode = OverlapMode::get(self.tcx, id.def_id.to_def_id());
+ let overlap_mode = OverlapMode::get(self.tcx, id.owner_id.to_def_id());
let impls_items = impls
.iter()
impl_def_id: LocalDefId,
) -> Result<(), ErrorGuaranteed> {
let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
- if let Some(err) = trait_ref.error_reported() {
- return Err(err);
- }
+ trait_ref.error_reported()?;
let ret = do_orphan_check_impl(tcx, trait_ref, impl_def_id);
if tcx.trait_is_auto(trait_ref.def_id) {
span_bug!(sp, "opaque type not found, but `has_opaque_types` is set")
}
- match traits::orphan_check(tcx, item.def_id.to_def_id()) {
+ match traits::orphan_check(tcx, item.owner_id.to_def_id()) {
Ok(()) => {}
Err(err) => emit_orphan_check_error(
tcx,
let item = tcx.hir().expect_item(def_id);
let hir::ItemKind::Impl(ref impl_) = item.kind else { bug!() };
- if let Some(trait_ref) = tcx.impl_trait_ref(item.def_id) {
+ if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) {
let trait_def = tcx.trait_def(trait_ref.def_id);
let unsafe_attr =
impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
"implementing the trait `{}` is not unsafe",
trait_ref.print_only_trait_path()
)
+ .span_suggestion_verbose(
+ item.span.with_hi(item.span.lo() + rustc_span::BytePos(7)),
+ "remove `unsafe` from this trait implementation",
+ "",
+ rustc_errors::Applicability::MachineApplicable,
+ )
.emit();
}
"the trait `{}` requires an `unsafe impl` declaration",
trait_ref.print_only_trait_path()
)
+ .note(format!(
+ "the trait `{}` enforces invariants that the compiler can't check. \
+ Review the trait documentation and make sure this implementation \
+ upholds those invariants before adding the `unsafe` keyword",
+ trait_ref.print_only_trait_path()
+ ))
+ .span_suggestion_verbose(
+ item.span.shrink_to_lo(),
+ "add `unsafe` to this trait implementation",
+ "unsafe ",
+ rustc_errors::Applicability::MaybeIncorrect,
+ )
.emit();
}
"requires an `unsafe impl` declaration due to `#[{}]` attribute",
attr_name
)
+ .note(format!(
+ "the trait `{}` enforces invariants that the compiler can't check. \
+ Review the trait documentation and make sure this implementation \
+ upholds those invariants before adding the `unsafe` keyword",
+ trait_ref.print_only_trait_path()
+ ))
+ .span_suggestion_verbose(
+ item.span.shrink_to_lo(),
+ "add `unsafe` to this trait implementation",
+ "unsafe ",
+ rustc_errors::Applicability::MaybeIncorrect,
+ )
.emit();
}
use rustc_hir::def::CtorKind;
use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::weak_lang_items;
-use rustc_hir::{GenericParamKind, Node};
+use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
+use rustc_hir::{lang_items, GenericParamKind, LangItem, Node};
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::mir::mono::Linkage;
self.tcx
}
- fn item_def_id(&self) -> Option<DefId> {
- Some(self.item_def_id)
+ fn item_def_id(&self) -> DefId {
+ self.item_def_id
}
fn get_type_parameter_bounds(
}
_ => {}
}
- err.emit();
- self.tcx().ty_error()
+ self.tcx().ty_error_with_guaranteed(err.emit())
}
}
fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
let it = tcx.hir().item(item_id);
debug!("convert: item {} with id {}", it.ident, it.hir_id());
- let def_id = item_id.def_id.def_id;
+ let def_id = item_id.owner_id.def_id;
match it.kind {
// These don't define types.
hir::ItemKind::ForeignMod { items, .. } => {
for item in items {
let item = tcx.hir().foreign_item(item.id);
- tcx.ensure().generics_of(item.def_id);
- tcx.ensure().type_of(item.def_id);
- tcx.ensure().predicates_of(item.def_id);
+ tcx.ensure().generics_of(item.owner_id);
+ tcx.ensure().type_of(item.owner_id);
+ tcx.ensure().predicates_of(item.owner_id);
match item.kind {
- hir::ForeignItemKind::Fn(..) => tcx.ensure().fn_sig(item.def_id),
+ hir::ForeignItemKind::Fn(..) => tcx.ensure().fn_sig(item.owner_id),
hir::ForeignItemKind::Static(..) => {
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_foreign_item(item);
}
}
}
- hir::ItemKind::Enum(ref enum_definition, _) => {
+ hir::ItemKind::Enum(..) => {
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().predicates_of(def_id);
- convert_enum_variant_types(tcx, def_id.to_def_id(), enum_definition.variants);
+ convert_enum_variant_types(tcx, def_id.to_def_id());
}
hir::ItemKind::Impl { .. } => {
tcx.ensure().generics_of(def_id);
}
if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
- convert_variant_ctor(tcx, ctor_hir_id);
+ let ctor_def_id = tcx.hir().local_def_id(ctor_hir_id);
+ convert_variant_ctor(tcx, ctor_def_id);
}
}
fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
let trait_item = tcx.hir().trait_item(trait_item_id);
- let def_id = trait_item_id.def_id;
+ let def_id = trait_item_id.owner_id;
tcx.ensure().generics_of(def_id);
match trait_item.kind {
}
fn convert_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) {
- let def_id = impl_item_id.def_id;
+ let def_id = impl_item_id.owner_id;
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().predicates_of(def_id);
}
}
-fn convert_variant_ctor(tcx: TyCtxt<'_>, ctor_id: hir::HirId) {
- let def_id = tcx.hir().local_def_id(ctor_id);
+fn convert_variant_ctor(tcx: TyCtxt<'_>, def_id: LocalDefId) {
tcx.ensure().generics_of(def_id);
tcx.ensure().type_of(def_id);
tcx.ensure().predicates_of(def_id);
}
-fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId, variants: &[hir::Variant<'_>]) {
+fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
let def = tcx.adt_def(def_id);
let repr_type = def.repr().discr_type();
let initial = repr_type.initial_discriminant(tcx);
let mut prev_discr = None::<Discr<'_>>;
// fill the discriminant values and field types
- for variant in variants {
+ for variant in def.variants() {
let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr(tcx));
prev_discr = Some(
- if let Some(ref e) = variant.disr_expr {
- let expr_did = tcx.hir().local_def_id(e.hir_id);
- def.eval_explicit_discr(tcx, expr_did.to_def_id())
+ if let ty::VariantDiscr::Explicit(const_def_id) = variant.discr {
+ def.eval_explicit_discr(tcx, const_def_id)
} else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) {
Some(discr)
} else {
- struct_span_err!(tcx.sess, variant.span, E0370, "enum discriminant overflowed")
- .span_label(
- variant.span,
- format!("overflowed on value after {}", prev_discr.unwrap()),
- )
+ let span = tcx.def_span(variant.def_id);
+ struct_span_err!(tcx.sess, span, E0370, "enum discriminant overflowed")
+ .span_label(span, format!("overflowed on value after {}", prev_discr.unwrap()))
.note(&format!(
"explicitly set `{} = {}` if that is desired outcome",
- variant.ident, wrapped_discr
+ tcx.item_name(variant.def_id),
+ wrapped_discr
))
.emit();
None
.unwrap_or(wrapped_discr),
);
- for f in variant.data.fields() {
- let def_id = tcx.hir().local_def_id(f.hir_id);
- tcx.ensure().generics_of(def_id);
- tcx.ensure().type_of(def_id);
- tcx.ensure().predicates_of(def_id);
+ for f in &variant.fields {
+ tcx.ensure().generics_of(f.did);
+ tcx.ensure().type_of(f.did);
+ tcx.ensure().predicates_of(f.did);
}
// Convert the ctor, if any. This also registers the variant as
// an item.
- if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
- convert_variant_ctor(tcx, ctor_hir_id);
+ if let Some(ctor_def_id) = variant.ctor_def_id {
+ convert_variant_ctor(tcx, ctor_def_id.expect_local());
}
}
}
match item {
Some(item) if matches!(item.kind, hir::AssocItemKind::Fn { .. }) => {
- if !tcx.impl_defaultness(item.id.def_id).has_value() {
+ if !tcx.impl_defaultness(item.id.owner_id).has_value() {
tcx.sess
.struct_span_err(
item.span,
}
ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
- // Do not try to inference the return type for a impl method coming from a trait
+ // Do not try to infer the return type for a impl method coming from a trait
if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) =
tcx.hir().get(tcx.hir().get_parent_node(hir_id))
&& i.of_trait.is_some()
fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
let icx = ItemCtxt::new(tcx, def_id);
- match tcx.hir().expect_item(def_id.expect_local()).kind {
+ let item = tcx.hir().expect_item(def_id.expect_local());
+ match item.kind {
hir::ItemKind::Impl(ref impl_) => impl_.of_trait.as_ref().map(|ast_trait_ref| {
let selfty = tcx.type_of(def_id);
- <dyn AstConv<'_>>::instantiate_mono_trait_ref(&icx, ast_trait_ref, selfty)
+ <dyn AstConv<'_>>::instantiate_mono_trait_ref(
+ &icx,
+ ast_trait_ref,
+ selfty,
+ check_impl_constness(tcx, impl_.constness, ast_trait_ref),
+ )
}),
_ => bug!(),
}
}
+fn check_impl_constness(
+ tcx: TyCtxt<'_>,
+ constness: hir::Constness,
+ ast_trait_ref: &hir::TraitRef<'_>,
+) -> ty::BoundConstness {
+ match constness {
+ hir::Constness::Const => {
+ if let Some(trait_def_id) = ast_trait_ref.trait_def_id() && !tcx.has_attr(trait_def_id, sym::const_trait) {
+ let trait_name = tcx.item_name(trait_def_id).to_string();
+ tcx.sess.emit_err(errors::ConstImplForNonConstTrait {
+ trait_ref_span: ast_trait_ref.path.span,
+ trait_name,
+ local_trait_span: trait_def_id.as_local().map(|_| tcx.def_span(trait_def_id).shrink_to_lo()),
+ marking: (),
+ adding: (),
+ });
+ ty::BoundConstness::NotConst
+ } else {
+ ty::BoundConstness::ConstIfConst
+ }
+ },
+ hir::Constness::NotConst => ty::BoundConstness::NotConst,
+ }
+}
+
fn impl_polarity(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ImplPolarity {
let is_rustc_reservation = tcx.has_attr(def_id, sym::rustc_reservation_impl);
let item = tcx.hir().expect_item(def_id.expect_local());
// strippable by the linker.
//
// Additionally weak lang items have predetermined symbol names.
- if tcx.is_weak_lang_item(did.to_def_id()) {
+ if WEAK_LANG_ITEMS.iter().any(|&l| tcx.lang_items().get(l) == Some(did.to_def_id())) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
}
- if let Some(name) = weak_lang_items::link_name(attrs) {
- codegen_fn_attrs.export_name = Some(name);
- codegen_fn_attrs.link_name = Some(name);
+ if let Some((name, _)) = lang_items::extract(attrs)
+ && let Some(lang_item) = LangItem::from_name(name)
+ && let Some(link_name) = lang_item.link_name()
+ {
+ codegen_fn_attrs.export_name = Some(link_name);
+ codegen_fn_attrs.link_name = Some(link_name);
}
check_link_name_xor_ordinal(tcx, &codegen_fn_attrs, link_ordinal_span);
// Now create the real type and const parameters.
let type_start = own_start - has_self as u32 + params.len() as u32;
let mut i = 0;
+ let mut next_index = || {
+ let prev = i;
+ i += 1;
+ prev as u32 + type_start
+ };
const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \
`struct`, `enum`, `type`, or `trait` definitions";
let kind = ty::GenericParamDefKind::Type { has_default: default.is_some(), synthetic };
- let param_def = ty::GenericParamDef {
- index: type_start + i as u32,
+ Some(ty::GenericParamDef {
+ index: next_index(),
name: param.name.ident().name,
def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
pure_wrt_drop: param.pure_wrt_drop,
kind,
- };
- i += 1;
- Some(param_def)
+ })
}
GenericParamKind::Const { default, .. } => {
if !matches!(allow_defaults, Defaults::Allowed) && default.is_some() {
);
}
- let param_def = ty::GenericParamDef {
- index: type_start + i as u32,
+ Some(ty::GenericParamDef {
+ index: next_index(),
name: param.name.ident().name,
def_id: tcx.hir().local_def_id(param.hir_id).to_def_id(),
pure_wrt_drop: param.pure_wrt_drop,
kind: ty::GenericParamDefKind::Const { has_default: default.is_some() },
- };
- i += 1;
- Some(param_def)
+ })
}
}));
&["<closure_kind>", "<closure_signature>", "<upvars>"][..]
};
- params.extend(dummy_args.iter().enumerate().map(|(i, &arg)| ty::GenericParamDef {
- index: type_start + i as u32,
+ params.extend(dummy_args.iter().map(|&arg| ty::GenericParamDef {
+ index: next_index(),
name: Symbol::intern(arg),
def_id,
pure_wrt_drop: false,
let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
if let Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) = parent_node {
params.push(ty::GenericParamDef {
- index: type_start,
+ index: next_index(),
name: Symbol::intern("<const_ty>"),
def_id,
pure_wrt_drop: false,
use rustc_middle::hir::map::Map;
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::resolve_lifetime::*;
-use rustc_middle::ty::{self, DefIdTree, TyCtxt};
+use rustc_middle::ty::{self, DefIdTree, TyCtxt, TypeSuperVisitable, TypeVisitor};
use rustc_span::def_id::DefId;
use rustc_span::symbol::{sym, Ident};
use rustc_span::Span;
/// `resolve_lifetimes`.
fn resolve_lifetimes_for<'tcx>(tcx: TyCtxt<'tcx>, def_id: hir::OwnerId) -> &'tcx ResolveLifetimes {
let item_id = item_for(tcx, def_id.def_id);
- let local_def_id = item_id.def_id.def_id;
- if item_id.def_id == def_id {
+ let local_def_id = item_id.owner_id.def_id;
+ if item_id.owner_id == def_id {
let item = tcx.hir().item(item_id);
match item.kind {
hir::ItemKind::Trait(..) => tcx.resolve_lifetimes_trait_definition(local_def_id),
// their owner, we can keep going until we find the Item that owns that. We then
// conservatively add all resolved lifetimes. Otherwise we run into problems in
// cases like `type Foo<'a> = impl Bar<As = impl Baz + 'a>`.
- for (_hir_id, node) in self.tcx.hir().parent_iter(item.def_id.into()) {
+ for (_hir_id, node) in self.tcx.hir().parent_iter(item.owner_id.into()) {
match node {
hir::Node::Item(parent_item) => {
let resolved_lifetimes: &ResolveLifetimes = self.tcx.resolve_lifetimes(
- item_for(self.tcx, parent_item.def_id.def_id).def_id.def_id,
+ item_for(self.tcx, parent_item.owner_id.def_id).owner_id.def_id,
);
// We need to add *all* deps, since opaque tys may want them from *us*
for (&owner, defs) in resolved_lifetimes.defs.iter() {
} else if let Some(body_id) = outermost_body {
let fn_id = self.tcx.hir().body_owner(body_id);
match self.tcx.hir().get(fn_id) {
- Node::Item(&hir::Item { kind: hir::ItemKind::Fn(..), .. })
- | Node::TraitItem(&hir::TraitItem {
+ Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. })
+ | Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Fn(..), ..
})
- | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }) => {
+ | Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. })
+ | Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. }) => {
let scope = self.tcx.hir().local_def_id(fn_id);
def = Region::Free(scope.to_def_id(), def.id().unwrap());
}
let mut late_bound = FxIndexSet::default();
- let mut constrained_by_input = ConstrainedCollector::default();
+ let mut constrained_by_input = ConstrainedCollector { regions: Default::default(), tcx };
for arg_ty in decl.inputs {
constrained_by_input.visit_ty(arg_ty);
}
debug!(?late_bound);
return Some(tcx.arena.alloc(late_bound));
- #[derive(Default)]
- struct ConstrainedCollector {
+ /// Visits a `ty::Ty` collecting information about what generic parameters are constrained.
+ ///
+ /// The visitor does not operate on `hir::Ty` so that it can be called on the rhs of a `type Alias<...> = ...;`
+ /// which may live in a separate crate so there would not be any hir available. Instead we use the `type_of`
+ /// query to obtain a `ty::Ty` which will be present even in cross crate scenarios. It also naturally
+ /// handles cycle detection as we go through the query system.
+ ///
+ /// This is necessary in the first place for the following case:
+ /// ```
+ /// type Alias<'a, T> = <T as Trait<'a>>::Assoc;
+ /// fn foo<'a>(_: Alias<'a, ()>) -> Alias<'a, ()> { ... }
+ /// ```
+ ///
+ /// If we conservatively considered `'a` unconstrained then we could break users who had written code before
+ /// we started correctly handling aliases. If we considered `'a` constrained then it would become late bound
+ /// causing an error during astconv as the `'a` is not constrained by the input type `<() as Trait<'a>>::Assoc`
+ /// but appears in the output type `<() as Trait<'a>>::Assoc`.
+ ///
+ /// We must therefore "look into" the `Alias` to see whether we should consider `'a` constrained or not.
+ ///
+ /// See #100508 #85533 #47511 for additional context
+ struct ConstrainedCollectorPostAstConv {
+ arg_is_constrained: Box<[bool]>,
+ }
+
+ use std::ops::ControlFlow;
+ use ty::Ty;
+ impl<'tcx> TypeVisitor<'tcx> for ConstrainedCollectorPostAstConv {
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<!> {
+ match t.kind() {
+ ty::Param(param_ty) => {
+ self.arg_is_constrained[param_ty.index as usize] = true;
+ }
+ ty::Projection(_) => return ControlFlow::Continue(()),
+ _ => (),
+ }
+ t.super_visit_with(self)
+ }
+
+ fn visit_const(&mut self, _: ty::Const<'tcx>) -> ControlFlow<!> {
+ ControlFlow::Continue(())
+ }
+
+ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<!> {
+ debug!("r={:?}", r.kind());
+ if let ty::RegionKind::ReEarlyBound(region) = r.kind() {
+ self.arg_is_constrained[region.index as usize] = true;
+ }
+
+ ControlFlow::Continue(())
+ }
+ }
+
+ struct ConstrainedCollector<'tcx> {
+ tcx: TyCtxt<'tcx>,
regions: FxHashSet<LocalDefId>,
}
- impl<'v> Visitor<'v> for ConstrainedCollector {
+ impl<'v> Visitor<'v> for ConstrainedCollector<'_> {
fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
match ty.kind {
hir::TyKind::Path(
// (defined above)
}
+ hir::TyKind::Path(hir::QPath::Resolved(
+ None,
+ hir::Path { res: Res::Def(DefKind::TyAlias, alias_def), segments, span },
+ )) => {
+ // See comments on `ConstrainedCollectorPostAstConv` for why this arm does not just consider
+ // substs to be unconstrained.
+ let generics = self.tcx.generics_of(alias_def);
+ let mut walker = ConstrainedCollectorPostAstConv {
+ arg_is_constrained: vec![false; generics.params.len()].into_boxed_slice(),
+ };
+ walker.visit_ty(self.tcx.type_of(alias_def));
+
+ match segments.last() {
+ Some(hir::PathSegment { args: Some(args), .. }) => {
+ let tcx = self.tcx;
+ for constrained_arg in
+ args.args.iter().enumerate().flat_map(|(n, arg)| {
+ match walker.arg_is_constrained.get(n) {
+ Some(true) => Some(arg),
+ Some(false) => None,
+ None => {
+ tcx.sess.delay_span_bug(
+ *span,
+ format!(
+ "Incorrect generic arg count for alias {:?}",
+ alias_def
+ ),
+ );
+ None
+ }
+ }
+ })
+ {
+ self.visit_generic_arg(constrained_arg);
+ }
+ }
+ Some(_) => (),
+ None => bug!("Path with no segments or self type"),
+ }
+ }
+
hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => {
// consider only the lifetimes on the final
// segment; I am not sure it's even currently
} else {
if matches!(def_kind, DefKind::AnonConst) && tcx.lazy_normalization() {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
+ let parent_def_id = tcx.hir().get_parent_item(hir_id);
+
if tcx.hir().opt_const_param_default_param_hir_id(hir_id).is_some() {
// In `generics_of` we set the generics' parent to be our parent's parent which means that
// we lose out on the predicates of our actual parent if we dont return those predicates here.
// parent of generics returned by `generics_of`
//
// In the above code we want the anon const to have predicates in its param env for `T: Trait`
- let item_def_id = tcx.hir().get_parent_item(hir_id);
- // In the above code example we would be calling `explicit_predicates_of(Foo)` here
+ // and we would be calling `explicit_predicates_of(Foo)` here
+ return tcx.explicit_predicates_of(parent_def_id);
+ }
+
+ let parent_def_kind = tcx.def_kind(parent_def_id);
+ if matches!(parent_def_kind, DefKind::OpaqueTy) {
+ // In `instantiate_identity` we inherit the predicates of our parent.
+ // However, opaque types do not have a parent (see `gather_explicit_predicates_of`), which means
+ // that we lose out on the predicates of our actual parent if we dont return those predicates here.
+ //
+ //
+ // fn foo<T: Trait>() -> impl Iterator<Output = Another<{ <T as Trait>::ASSOC }> > { todo!() }
+ // ^^^^^^^^^^^^^^^^^^^ the def id we are calling
+ // explicit_predicates_of on
+ //
+ // In the above code we want the anon const to have predicates in its param env for `T: Trait`.
+ // However, the anon const cannot inherit predicates from its parent since it's opaque.
+ //
+ // To fix this, we call `explicit_predicates_of` directly on `foo`, the parent's parent.
+
+ // In the above example this is `foo::{opaque#0}` or `impl Iterator`
+ let parent_hir_id = tcx.hir().local_def_id_to_hir_id(parent_def_id.def_id);
+
+ // In the above example this is the function `foo`
+ let item_def_id = tcx.hir().get_parent_item(parent_hir_id);
+
+ // In the above code example we would be calling `explicit_predicates_of(foo)` here
return tcx.explicit_predicates_of(item_def_id);
}
}
}
}
ItemKind::TyAlias(self_ty, _) => icx.to_ty(self_ty),
- ItemKind::Impl(hir::Impl { self_ty, .. }) => icx.to_ty(*self_ty),
+ ItemKind::Impl(hir::Impl { self_ty, .. }) => {
+ match self_ty.find_self_aliases() {
+ spans if spans.len() > 0 => {
+ tcx.sess.emit_err(crate::errors::SelfInImplSelf { span: spans.into(), note: (), });
+ tcx.ty_error()
+ },
+ _ => icx.to_ty(*self_ty),
+ }
+ },
ItemKind::Fn(..) => {
let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
tcx.mk_fn_def(def_id.to_def_id(), substs)
intravisit::walk_expr(self, ex);
}
fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
- trace!(?it.def_id);
+ trace!(?it.owner_id);
// The opaque type itself or its children are not within its reveal scope.
- if it.def_id.def_id != self.def_id {
- self.check(it.def_id.def_id);
+ if it.owner_id.def_id != self.def_id {
+ self.check(it.owner_id.def_id);
intravisit::walk_item(self, it);
}
}
fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
- trace!(?it.def_id);
+ trace!(?it.owner_id);
// The opaque type itself or its children are not within its reveal scope.
- if it.def_id.def_id != self.def_id {
- self.check(it.def_id.def_id);
+ if it.owner_id.def_id != self.def_id {
+ self.check(it.owner_id.def_id);
intravisit::walk_impl_item(self, it);
}
}
fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
- trace!(?it.def_id);
- self.check(it.def_id.def_id);
+ trace!(?it.owner_id);
+ self.check(it.owner_id.def_id);
intravisit::walk_trait_item(self, it);
}
}
}
let Some(hidden) = locator.found else {
- tcx.sess.emit_err(UnconstrainedOpaqueType {
+ let reported = tcx.sess.emit_err(UnconstrainedOpaqueType {
span: tcx.def_span(def_id),
name: tcx.item_name(tcx.local_parent(def_id).to_def_id()),
+ what: match tcx.hir().get(scope) {
+ _ if scope == hir::CRATE_HIR_ID => "module",
+ Node::Item(hir::Item { kind: hir::ItemKind::Mod(_), .. }) => "module",
+ Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => "impl",
+ _ => "item",
+ },
});
- return tcx.ty_error();
+ return tcx.ty_error_with_guaranteed(reported);
};
// Only check against typeck if we didn't already error
intravisit::walk_expr(self, ex);
}
fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
- trace!(?it.def_id);
+ trace!(?it.owner_id);
// The opaque type itself or its children are not within its reveal scope.
- if it.def_id.def_id != self.def_id {
- self.check(it.def_id.def_id);
+ if it.owner_id.def_id != self.def_id {
+ self.check(it.owner_id.def_id);
intravisit::walk_item(self, it);
}
}
fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
- trace!(?it.def_id);
+ trace!(?it.owner_id);
// The opaque type itself or its children are not within its reveal scope.
- if it.def_id.def_id != self.def_id {
- self.check(it.def_id.def_id);
+ if it.owner_id.def_id != self.def_id {
+ self.check(it.owner_id.def_id);
intravisit::walk_impl_item(self, it);
}
}
fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
- trace!(?it.def_id);
- self.check(it.def_id.def_id);
+ trace!(?it.owner_id);
+ self.check(it.owner_id.def_id);
intravisit::walk_trait_item(self, it);
}
}
//! Errors emitted by `rustc_hir_analysis`.
-use rustc_errors::IntoDiagnostic;
use rustc_errors::{error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler};
+use rustc_errors::{IntoDiagnostic, MultiSpan};
use rustc_macros::{Diagnostic, LintDiagnostic};
use rustc_middle::ty::Ty;
use rustc_span::{symbol::Ident, Span, Symbol};
#[primary_span]
#[label]
pub span: Span,
- #[suggestion_verbose(code = "{ty}")]
+ #[suggestion(style = "verbose", code = "{ty}")]
pub opt_sugg: Option<(Span, Applicability)>,
}
#[primary_span]
pub span: Span,
pub name: Symbol,
+ pub what: &'static str,
}
pub struct MissingTypeParams {
// Manual implementation of `IntoDiagnostic` to be able to call `span_to_snippet`.
impl<'a> IntoDiagnostic<'a> for MissingTypeParams {
+ #[track_caller]
fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
let mut err = handler.struct_span_err_with_code(
self.span,
#[derive(LintDiagnostic)]
#[diag(hir_analysis_extern_crate_not_idiomatic)]
pub struct ExternCrateNotIdiomatic {
- #[suggestion_short(applicability = "machine-applicable", code = "{suggestion_code}")]
+ #[suggestion(
+ style = "short",
+ applicability = "machine-applicable",
+ code = "{suggestion_code}"
+ )]
pub span: Span,
pub msg_code: String,
pub suggestion_code: String,
#[primary_span]
pub span: Span,
}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_const_impl_for_non_const_trait)]
+pub struct ConstImplForNonConstTrait {
+ #[primary_span]
+ pub trait_ref_span: Span,
+ pub trait_name: String,
+ #[suggestion(applicability = "machine-applicable", code = "#[const_trait]")]
+ pub local_trait_span: Option<Span>,
+ #[note]
+ pub marking: (),
+ #[note(adding)]
+ pub adding: (),
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_const_bound_for_non_const_trait)]
+pub struct ConstBoundForNonConstTrait {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_self_in_impl_self)]
+pub struct SelfInImplSelf {
+ #[primary_span]
+ pub span: MultiSpan,
+ #[note]
+ pub note: (),
+}
let min_specialization = tcx.features().min_specialization;
let module = tcx.hir_module_items(module_def_id);
for id in module.items() {
- if matches!(tcx.def_kind(id.def_id), DefKind::Impl) {
- enforce_impl_params_are_constrained(tcx, id.def_id.def_id);
+ if matches!(tcx.def_kind(id.owner_id), DefKind::Impl) {
+ enforce_impl_params_are_constrained(tcx, id.owner_id.def_id);
if min_specialization {
- check_min_specialization(tcx, id.def_id.def_id);
+ check_min_specialization(tcx, id.owner_id.def_id);
}
}
}
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- ocx.infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ ocx.infcx.err_ctxt().report_fulfillment_errors(&errors, None);
return None;
}
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::util;
-use rustc_session::config::EntryFnType;
+use rustc_session::{config::EntryFnType, parse::feature_err};
use rustc_span::{symbol::sym, Span, DUMMY_SP};
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
use bounds::Bounds;
fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) {
- match (decl.c_variadic, abi) {
- // The function has the correct calling convention, or isn't a "C-variadic" function.
- (false, _) | (true, Abi::C { .. }) | (true, Abi::Cdecl { .. }) => {}
- // The function is a "C-variadic" function with an incorrect calling convention.
- (true, _) => {
- let mut err = struct_span_err!(
- tcx.sess,
+ const ERROR_HEAD: &str = "C-variadic function must have a compatible calling convention";
+ const CONVENTIONS_UNSTABLE: &str = "`C`, `cdecl`, `win64`, `sysv64` or `efiapi`";
+ const CONVENTIONS_STABLE: &str = "`C` or `cdecl`";
+ const UNSTABLE_EXPLAIN: &str =
+ "using calling conventions other than `C` or `cdecl` for varargs functions is unstable";
+
+ if !decl.c_variadic || matches!(abi, Abi::C { .. } | Abi::Cdecl { .. }) {
+ return;
+ }
+
+ let extended_abi_support = tcx.features().extended_varargs_abi_support;
+ let conventions = match (extended_abi_support, abi.supports_varargs()) {
+ // User enabled additional ABI support for varargs and function ABI matches those ones.
+ (true, true) => return,
+
+ // Using this ABI would be ok, if the feature for additional ABI support was enabled.
+ // Return CONVENTIONS_STABLE, because we want the other error to look the same.
+ (false, true) => {
+ feature_err(
+ &tcx.sess.parse_sess,
+ sym::extended_varargs_abi_support,
span,
- E0045,
- "C-variadic function must have C or cdecl calling convention"
- );
- err.span_label(span, "C-variadics require C or cdecl calling convention").emit();
+ UNSTABLE_EXPLAIN,
+ )
+ .emit();
+ CONVENTIONS_STABLE
}
- }
+
+ (false, false) => CONVENTIONS_STABLE,
+ (true, false) => CONVENTIONS_UNSTABLE,
+ };
+
+ let mut err = struct_span_err!(tcx.sess, span, E0045, "{}, like {}", ERROR_HEAD, conventions);
+ err.span_label(span, ERROR_HEAD).emit();
}
fn require_same_types<'tcx>(
match &errors[..] {
[] => true,
errors => {
- infcx.err_ctxt().report_fulfillment_errors(errors, None, false);
+ infcx.err_ctxt().report_fulfillment_errors(errors, None);
false
}
}
ocx.register_bound(cause, param_env, norm_return_ty, term_did);
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
- infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None);
error = true;
}
// now we can take the return type of the given main function
error = true;
}
if let hir::IsAsync::Async = sig.header.asyncness {
- let span = tcx.def_span(it.def_id);
+ let span = tcx.def_span(it.owner_id);
struct_span_err!(
tcx.sess,
span,
// Visit all the crates and infer predicates
for id in tcx.hir().items() {
- let item_did = id.def_id;
+ let item_did = id.owner_id;
debug!("InferVisitor::visit_item(item={:?})", item_did);
for id in tcx.hir().items() {
// For unit testing: check for a special "rustc_outlives"
// attribute and report an error with various results if found.
- if tcx.has_attr(id.def_id.to_def_id(), sym::rustc_outlives) {
- let inferred_outlives_of = tcx.inferred_outlives_of(id.def_id);
+ if tcx.has_attr(id.owner_id.to_def_id(), sym::rustc_outlives) {
+ let inferred_outlives_of = tcx.inferred_outlives_of(id.owner_id);
struct_span_err!(
tcx.sess,
- tcx.def_span(id.def_id),
+ tcx.def_span(id.owner_id),
E0640,
"{:?}",
inferred_outlives_of
// For unit testing: check for a special "rustc_variance"
// attribute and report an error with various results if found.
for id in tcx.hir().items() {
- if tcx.has_attr(id.def_id.to_def_id(), sym::rustc_variance) {
- let variances_of = tcx.variances_of(id.def_id);
- struct_span_err!(tcx.sess, tcx.def_span(id.def_id), E0208, "{:?}", variances_of).emit();
+ if tcx.has_attr(id.owner_id.to_def_id(), sym::rustc_variance) {
+ let variances_of = tcx.variances_of(id.owner_id);
+ struct_span_err!(tcx.sess, tcx.def_span(id.owner_id), E0208, "{:?}", variances_of)
+ .emit();
}
}
}
use crate::coercion::{AsCoercionSite, CoerceMany};
use crate::{Diverges, Expectation, FnCtxt, Needs};
-use rustc_errors::{Applicability, MultiSpan};
+use rustc_errors::{Applicability, Diagnostic, MultiSpan};
use rustc_hir::{self as hir, ExprKind};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::traits::Obligation;
Some(&arm.body),
arm_ty,
Some(&mut |err| {
- let Some(ret) = self
- .tcx
- .hir()
- .find_by_def_id(self.body_id.owner.def_id)
- .and_then(|owner| owner.fn_decl())
- .map(|decl| decl.output.span())
- else { return; };
- let Expectation::IsLast(stmt) = orig_expected else {
- return
- };
- let can_coerce_to_return_ty = match self.ret_coercion.as_ref() {
- Some(ret_coercion) if self.in_tail_expr => {
- let ret_ty = ret_coercion.borrow().expected_ty();
- let ret_ty = self.inh.infcx.shallow_resolve(ret_ty);
- self.can_coerce(arm_ty, ret_ty)
- && prior_arm.map_or(true, |(_, t, _)| self.can_coerce(t, ret_ty))
- // The match arms need to unify for the case of `impl Trait`.
- && !matches!(ret_ty.kind(), ty::Opaque(..))
- }
- _ => false,
- };
- if !can_coerce_to_return_ty {
- return;
- }
-
- let semi_span = expr.span.shrink_to_hi().with_hi(stmt.hi());
- let mut ret_span: MultiSpan = semi_span.into();
- ret_span.push_span_label(
- expr.span,
- "this could be implicitly returned but it is a statement, not a \
- tail expression",
- );
- ret_span
- .push_span_label(ret, "the `match` arms can conform to this return type");
- ret_span.push_span_label(
- semi_span,
- "the `match` is a statement because of this semicolon, consider \
- removing it",
- );
- err.span_note(
- ret_span,
- "you might have meant to return the `match` expression",
- );
- err.tool_only_span_suggestion(
- semi_span,
- "remove this semicolon",
- "",
- Applicability::MaybeIncorrect,
- );
+ self.suggest_removing_semicolon_for_coerce(
+ err,
+ expr,
+ orig_expected,
+ arm_ty,
+ prior_arm,
+ )
}),
false,
);
coercion.complete(self)
}
+ fn suggest_removing_semicolon_for_coerce(
+ &self,
+ diag: &mut Diagnostic,
+ expr: &hir::Expr<'tcx>,
+ expectation: Expectation<'tcx>,
+ arm_ty: Ty<'tcx>,
+ prior_arm: Option<(Option<hir::HirId>, Ty<'tcx>, Span)>,
+ ) {
+ let hir = self.tcx.hir();
+
+ // First, check that we're actually in the tail of a function.
+ let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Block(block, _), .. }) =
+ hir.get(self.body_id) else { return; };
+ let Some(hir::Stmt { kind: hir::StmtKind::Semi(last_expr), .. })
+ = block.innermost_block().stmts.last() else { return; };
+ if last_expr.hir_id != expr.hir_id {
+ return;
+ }
+
+ // Next, make sure that we have no type expectation.
+ let Some(ret) = hir
+ .find_by_def_id(self.body_id.owner.def_id)
+ .and_then(|owner| owner.fn_decl())
+ .map(|decl| decl.output.span()) else { return; };
+ let Expectation::IsLast(stmt) = expectation else {
+ return;
+ };
+
+ let can_coerce_to_return_ty = match self.ret_coercion.as_ref() {
+ Some(ret_coercion) => {
+ let ret_ty = ret_coercion.borrow().expected_ty();
+ let ret_ty = self.inh.infcx.shallow_resolve(ret_ty);
+ self.can_coerce(arm_ty, ret_ty)
+ && prior_arm.map_or(true, |(_, ty, _)| self.can_coerce(ty, ret_ty))
+ // The match arms need to unify for the case of `impl Trait`.
+ && !matches!(ret_ty.kind(), ty::Opaque(..))
+ }
+ _ => false,
+ };
+ if !can_coerce_to_return_ty {
+ return;
+ }
+
+ let semi_span = expr.span.shrink_to_hi().with_hi(stmt.hi());
+ let mut ret_span: MultiSpan = semi_span.into();
+ ret_span.push_span_label(
+ expr.span,
+ "this could be implicitly returned but it is a statement, not a \
+ tail expression",
+ );
+ ret_span.push_span_label(ret, "the `match` arms can conform to this return type");
+ ret_span.push_span_label(
+ semi_span,
+ "the `match` is a statement because of this semicolon, consider \
+ removing it",
+ );
+ diag.span_note(ret_span, "you might have meant to return the `match` expression");
+ diag.tool_only_span_suggestion(
+ semi_span,
+ "remove this semicolon",
+ "",
+ Applicability::MaybeIncorrect,
+ );
+ }
+
/// When the previously checked expression (the scrutinee) diverges,
/// warn the user about the match arms being unreachable.
fn warn_arms_when_scrutinee_diverges(&self, arms: &'tcx [hir::Arm<'tcx>]) {
..
} = self.type_var_origin(expected)? else { return None; };
- let sig = *self
- .typeck_results
- .borrow()
- .liberated_fn_sigs()
- .get(hir::HirId::make_owner(self.body_id.owner.def_id))?;
+ let sig = self.body_fn_sig()?;
let substs = sig.output().walk().find_map(|arg| {
if let ty::GenericArgKind::Type(ty) = arg.unpack()
output
}
+ #[instrument(level = "debug", skip(self, call_expr, callee_expr, arg_exprs, autoderef), ret)]
fn try_overloaded_call_step(
&self,
call_expr: &'tcx hir::Expr<'tcx>,
) -> Option<CallStep<'tcx>> {
let adjusted_ty =
self.structurally_resolved_type(autoderef.span(), autoderef.final_ty(false));
- debug!(
- "try_overloaded_call_step(call_expr={:?}, adjusted_ty={:?})",
- call_expr, adjusted_ty
- );
// If the callee is a bare function or a closure, then we're all set.
match *adjusted_ty.kind() {
def_id,
);
+ if fn_sig.abi == abi::Abi::RustCall {
+ let sp = arg_exprs.last().map_or(call_expr.span, |expr| expr.span);
+ if let Some(ty) = fn_sig.inputs().last().copied() {
+ self.register_bound(
+ ty,
+ self.tcx.require_lang_item(hir::LangItem::Tuple, Some(sp)),
+ traits::ObligationCause::new(sp, self.body_id, traits::RustCall),
+ );
+ } else {
+ self.tcx.sess.span_err(
+ sp,
+ "functions with the \"rust-call\" ABI must take a single non-self tuple argument",
+ );
+ }
+ }
+
fn_sig.output()
}
cast_ty: Ty<'tcx>,
cast_span: Span,
span: Span,
+ /// whether the cast is made in a const context or not.
+ pub constness: hir::Constness,
}
/// The kind of pointer and associated metadata (thin, length or vtable) - we
debug!("pointer_kind({:?}, {:?})", t, span);
let t = self.resolve_vars_if_possible(t);
-
- if let Some(reported) = t.error_reported() {
- return Err(reported);
- }
+ t.error_reported()?;
if self.type_is_sized_modulo_regions(self.param_env, t, span) {
return Ok(Some(PointerKind::Thin));
cast_ty: Ty<'tcx>,
cast_span: Span,
span: Span,
+ constness: hir::Constness,
) -> Result<CastCheck<'tcx>, ErrorGuaranteed> {
let expr_span = expr.span.find_ancestor_inside(span).unwrap_or(expr.span);
- let check = CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span };
+ let check = CastCheck { expr, expr_ty, expr_span, cast_ty, cast_span, span, constness };
// For better error messages, check for some obviously unsized
// cases now. We do a more thorough check at the end, once
// inference is more completely known.
match cast_ty.kind() {
ty::Dynamic(_, _, ty::Dyn) | ty::Slice(..) => {
- let reported = check.report_cast_to_unsized_type(fcx);
- Err(reported)
+ Err(check.report_cast_to_unsized_type(fcx))
}
_ => Ok(check),
}
}
fn report_cast_to_unsized_type(&self, fcx: &FnCtxt<'a, 'tcx>) -> ErrorGuaranteed {
- if let Some(reported) =
- self.cast_ty.error_reported().or_else(|| self.expr_ty.error_reported())
- {
- return reported;
+ if let Err(err) = self.cast_ty.error_reported() {
+ return err;
+ }
+ if let Err(err) = self.expr_ty.error_reported() {
+ return err;
}
let tstr = fcx.ty_to_string(self.cast_ty);
(Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast),
- (_, DynStar) | (DynStar, _) => bug!("should be handled by `try_coerce`"),
+ (_, DynStar) | (DynStar, _) => {
+ if fcx.tcx.features().dyn_star {
+ bug!("should be handled by `try_coerce`")
+ } else {
+ Err(CastError::IllegalCast)
+ }
+ }
}
}
use rustc_hir::def::DefKind;
use rustc_hir::intravisit::Visitor;
use rustc_hir::lang_items::LangItem;
-use rustc_hir::{ImplicitSelfKind, ItemKind, Node};
use rustc_hir_analysis::check::fn_maybe_err;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::RegionVariableOrigin;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::def_id::LocalDefId;
-use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits;
use std::cell::RefCell;
fn_id: hir::HirId,
body: &'tcx hir::Body<'tcx>,
can_be_generator: Option<hir::Movability>,
- return_type_pre_known: bool,
) -> (FnCtxt<'a, 'tcx>, Option<GeneratorTypes<'tcx>>) {
// Create the function context. This is either derived from scratch or,
// in the case of closures, based on the outer context.
let mut fcx = FnCtxt::new(inherited, param_env, body.value.hir_id);
fcx.ps.set(UnsafetyState::function(fn_sig.unsafety, fn_id));
- fcx.return_type_pre_known = return_type_pre_known;
let tcx = fcx.tcx;
let hir = tcx.hir();
decl.output.span(),
param_env,
));
- // If we replaced declared_ret_ty with infer vars, then we must be inferring
- // an opaque type, so set a flag so we can improve diagnostics.
- fcx.return_type_has_opaque = ret_ty != declared_ret_ty;
fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(ret_ty)));
fn_maybe_err(tcx, span, fn_sig.abi);
- if fn_sig.abi == Abi::RustCall {
- let expected_args = if let ImplicitSelfKind::None = decl.implicit_self { 1 } else { 2 };
-
- let err = || {
- let item = match tcx.hir().get(fn_id) {
- Node::Item(hir::Item { kind: ItemKind::Fn(header, ..), .. }) => Some(header),
- Node::ImplItem(hir::ImplItem {
- kind: hir::ImplItemKind::Fn(header, ..), ..
- }) => Some(header),
- Node::TraitItem(hir::TraitItem {
- kind: hir::TraitItemKind::Fn(header, ..),
- ..
- }) => Some(header),
- // Closures are RustCall, but they tuple their arguments, so shouldn't be checked
- Node::Expr(hir::Expr { kind: hir::ExprKind::Closure { .. }, .. }) => None,
- node => bug!("Item being checked wasn't a function/closure: {:?}", node),
- };
-
- if let Some(header) = item {
- tcx.sess.span_err(header.span, "functions with the \"rust-call\" ABI must take a single non-self argument that is a tuple");
- }
- };
-
- if fn_sig.inputs().len() != expected_args {
- err()
- } else {
- // FIXME(CraftSpider) Add a check on parameter expansion, so we don't just make the ICE happen later on
- // This will probably require wide-scale changes to support a TupleKind obligation
- // We can't resolve this without knowing the type of the param
- if !matches!(fn_sig.inputs()[expected_args - 1].kind(), ty::Tuple(_) | ty::Param(_)) {
- err()
- }
- }
- }
-
if body.generator_kind.is_some() && can_be_generator.is_some() {
let yield_ty = fcx
.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span });
inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
- fcx.in_tail_expr = true;
if let ty::Dynamic(..) = declared_ret_ty.kind() {
// FIXME: We need to verify that the return type is `Sized` after the return expression has
// been evaluated so that we have types available for all the nodes being returned, but that
fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
fcx.check_return_expr(&body.value, false);
}
- fcx.in_tail_expr = false;
// We insert the deferred_generator_interiors entry after visiting the body.
// This ensures that all nested generators appear before the entry of this generator.
check_panic_info_fn(tcx, panic_impl_did.expect_local(), fn_sig, decl, declared_ret_ty);
}
- // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !`
- if let Some(alloc_error_handler_did) = tcx.lang_items().oom()
- && alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id()
- {
- check_alloc_error_fn(tcx, alloc_error_handler_did.expect_local(), fn_sig, decl, declared_ret_ty);
- }
-
(fcx, gen_ty)
}
tcx.sess.span_err(span, "should have no const parameters");
}
}
-
-fn check_alloc_error_fn(
- tcx: TyCtxt<'_>,
- fn_id: LocalDefId,
- fn_sig: ty::FnSig<'_>,
- decl: &hir::FnDecl<'_>,
- declared_ret_ty: Ty<'_>,
-) {
- let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() else {
- tcx.sess.err("language item required, but not found: `alloc_layout`");
- return;
- };
-
- if *declared_ret_ty.kind() != ty::Never {
- tcx.sess.span_err(decl.output.span(), "return type should be `!`");
- }
-
- let inputs = fn_sig.inputs();
- if inputs.len() != 1 {
- tcx.sess.span_err(tcx.def_span(fn_id), "function should have one argument");
- return;
- }
-
- let arg_is_alloc_layout = match inputs[0].kind() {
- ty::Adt(ref adt, _) => adt.did() == alloc_layout_did,
- _ => false,
- };
-
- if !arg_is_alloc_layout {
- tcx.sess.span_err(decl.inputs[0].span, "argument should be `Layout`");
- }
-
- let DefKind::Fn = tcx.def_kind(fn_id) else {
- let span = tcx.def_span(fn_id);
- tcx.sess.span_err(span, "`#[alloc_error_handler]` should be a function");
- return;
- };
-
- let generic_counts = tcx.generics_of(fn_id).own_counts();
- if generic_counts.types != 0 {
- let span = tcx.def_span(fn_id);
- tcx.sess.span_err(span, "`#[alloc_error_handler]` function should have no type parameters");
- }
- if generic_counts.consts != 0 {
- let span = tcx.def_span(fn_id);
- tcx.sess
- .span_err(span, "`#[alloc_error_handler]` function should have no const parameters");
- }
-}
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_infer::infer::{InferOk, InferResult};
+use rustc_macros::{TypeFoldable, TypeVisitable};
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{self, Ty};
use rustc_span::source_map::Span;
use rustc_target::spec::abi::Abi;
+use rustc_trait_selection::traits;
use rustc_trait_selection::traits::error_reporting::ArgKind;
use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
use std::cmp;
use std::iter;
/// What signature do we *expect* the closure to have from context?
-#[derive(Debug)]
+#[derive(Debug, Clone, TypeFoldable, TypeVisitable)]
struct ExpectedSig<'tcx> {
/// Span that gave us this expectation, if we know that.
cause_span: Option<Span>,
debug!(?bound_sig, ?liberated_sig);
- let return_type_pre_known = !liberated_sig.output().is_ty_infer();
-
let generator_types = check_fn(
self,
self.param_env.without_const(),
expr.hir_id,
body,
gen,
- return_type_pre_known,
)
.1;
&self,
expected_vid: ty::TyVid,
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
- let expected_sig =
- self.obligations_for_self_ty(expected_vid).find_map(|(_, obligation)| {
- debug!(?obligation.predicate);
-
- let bound_predicate = obligation.predicate.kind();
- if let ty::PredicateKind::Projection(proj_predicate) =
- obligation.predicate.kind().skip_binder()
- {
- // Given a Projection predicate, we can potentially infer
- // the complete signature.
+ let mut expected_sig = None;
+ let mut expected_kind = None;
+
+ for obligation in traits::elaborate_obligations(
+ self.tcx,
+ // Reverse the obligations here, since `elaborate_*` uses a stack,
+ // and we want to keep inference generally in the same order of
+ // the registered obligations.
+ self.obligations_for_self_ty(expected_vid).rev().collect(),
+ ) {
+ debug!(?obligation.predicate);
+ let bound_predicate = obligation.predicate.kind();
+
+ // Given a Projection predicate, we can potentially infer
+ // the complete signature.
+ if expected_sig.is_none()
+ && let ty::PredicateKind::Projection(proj_predicate) = bound_predicate.skip_binder()
+ {
+ expected_sig = self.normalize_associated_types_in(
+ obligation.cause.span,
self.deduce_sig_from_projection(
- Some(obligation.cause.span),
+ Some(obligation.cause.span),
bound_predicate.rebind(proj_predicate),
- )
- } else {
- None
- }
- });
+ ),
+ );
+ }
- // Even if we can't infer the full signature, we may be able to
- // infer the kind. This can occur when we elaborate a predicate
- // like `F : Fn<A>`. Note that due to subtyping we could encounter
- // many viable options, so pick the most restrictive.
- let expected_kind = self
- .obligations_for_self_ty(expected_vid)
- .filter_map(|(tr, _)| self.tcx.fn_trait_kind_from_lang_item(tr.def_id()))
- .fold(None, |best, cur| Some(best.map_or(cur, |best| cmp::min(best, cur))));
+ // Even if we can't infer the full signature, we may be able to
+ // infer the kind. This can occur when we elaborate a predicate
+ // like `F : Fn<A>`. Note that due to subtyping we could encounter
+ // many viable options, so pick the most restrictive.
+ let trait_def_id = match bound_predicate.skip_binder() {
+ ty::PredicateKind::Projection(data) => {
+ Some(data.projection_ty.trait_def_id(self.tcx))
+ }
+ ty::PredicateKind::Trait(data) => Some(data.def_id()),
+ _ => None,
+ };
+ if let Some(closure_kind) =
+ trait_def_id.and_then(|def_id| self.tcx.fn_trait_kind_from_lang_item(def_id))
+ {
+ expected_kind = Some(
+ expected_kind
+ .map_or_else(|| closure_kind, |current| cmp::min(current, closure_kind)),
+ );
+ }
+ }
(expected_sig, expected_kind)
}
let output_ty = match *ret_ty.kind() {
ty::Infer(ty::TyVar(ret_vid)) => {
- self.obligations_for_self_ty(ret_vid).find_map(|(_, obligation)| {
+ self.obligations_for_self_ty(ret_vid).find_map(|obligation| {
get_future_output(obligation.predicate, obligation.cause.span)
})?
}
// Object safety violations or miscellaneous.
Err(err) => {
- self.err_ctxt().report_selection_error(
- obligation.clone(),
- &obligation,
- &err,
- false,
- );
+ self.err_ctxt().report_selection_error(obligation.clone(), &obligation, &err);
// Treat this like an obligation and follow through
// with the unsizing - the lack of a coercion should
// be silent, as it causes a type mismatch later.
if visitor.ret_exprs.len() > 0 && let Some(expr) = expression {
self.note_unreachable_loop_return(&mut err, &expr, &visitor.ret_exprs);
}
- err.emit_unless(unsized_return);
+ let reported = err.emit_unless(unsized_return);
- self.final_ty = Some(fcx.tcx.ty_error());
+ self.final_ty = Some(fcx.tcx.ty_error_with_guaranteed(reported));
}
}
}
// may occur at the first return expression we see in the closure
// (if it conflicts with the declared return type). Skip adding a
// note in this case, since it would be incorrect.
- && !fcx.return_type_pre_known
+ && let Some(fn_sig) = fcx.body_fn_sig()
+ && fn_sig.output().is_ty_var()
{
err.span_note(
sp,
checked_ty: Ty<'tcx>,
hir_id: hir::HirId,
) -> Vec<AssocItem> {
- let mut methods =
- self.probe_for_return_type(span, probe::Mode::MethodCall, expected, checked_ty, hir_id);
- methods.retain(|m| {
- self.has_only_self_parameter(m)
- && self
- .tcx
- // This special internal attribute is used to permit
- // "identity-like" conversion methods to be suggested here.
- //
- // FIXME (#46459 and #46460): ideally
- // `std::convert::Into::into` and `std::borrow:ToOwned` would
- // also be `#[rustc_conversion_suggestion]`, if not for
- // method-probing false-positives and -negatives (respectively).
- //
- // FIXME? Other potential candidate methods: `as_ref` and
- // `as_mut`?
- .has_attr(m.def_id, sym::rustc_conversion_suggestion)
- });
+ let methods = self.probe_for_return_type(
+ span,
+ probe::Mode::MethodCall,
+ expected,
+ checked_ty,
+ hir_id,
+ |m| {
+ self.has_only_self_parameter(m)
+ && self
+ .tcx
+ // This special internal attribute is used to permit
+ // "identity-like" conversion methods to be suggested here.
+ //
+ // FIXME (#46459 and #46460): ideally
+ // `std::convert::Into::into` and `std::borrow:ToOwned` would
+ // also be `#[rustc_conversion_suggestion]`, if not for
+ // method-probing false-positives and -negatives (respectively).
+ //
+ // FIXME? Other potential candidate methods: `as_ref` and
+ // `as_mut`?
+ .has_attr(m.def_id, sym::rustc_conversion_suggestion)
+ },
+ );
methods
}
}
#[derive(Subdiagnostic)]
-#[multipart_suggestion_verbose(
+#[multipart_suggestion(
hir_analysis_add_missing_parentheses_in_range,
+ style = "verbose",
applicability = "maybe-incorrect"
)]
pub struct AddMissingParenthesesInRange {
// coercions from ! to `expected`.
if ty.is_never() {
if let Some(adjustments) = self.typeck_results.borrow().adjustments().get(expr.hir_id) {
- self.tcx().sess.delay_span_bug(
+ let reported = self.tcx().sess.delay_span_bug(
expr.span,
"expression with never type wound up being adjusted",
);
return if let [Adjustment { kind: Adjust::NeverToAny, target }] = &adjustments[..] {
target.to_owned()
} else {
- self.tcx().ty_error()
+ self.tcx().ty_error_with_guaranteed(reported)
};
}
// Hide the outer diverging and has_errors flags.
let old_diverges = self.diverges.replace(Diverges::Maybe);
- let old_has_errors = self.has_errors.replace(false);
let ty = ensure_sufficient_stack(|| match &expr.kind {
hir::ExprKind::Path(
// Combine the diverging and has_error flags.
self.diverges.set(self.diverges.get() | old_diverges);
- self.has_errors.set(self.has_errors.get() | old_has_errors);
debug!("type of {} is...", self.tcx.hir().node_to_string(expr.hir_id));
debug!("... {:?}, expected is {:?}", ty, expected);
{
err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
}
- err.emit();
- oprnd_t = tcx.ty_error();
+ oprnd_t = tcx.ty_error_with_guaranteed(err.emit());
}
}
hir::UnOp::Not => {
return_expr_ty,
);
- if self.return_type_has_opaque {
+ if let Some(fn_sig) = self.body_fn_sig()
+ && fn_sig.output().has_opaque_types()
+ {
// Point any obligations that were registered due to opaque type
// inference at the return expression.
- self.select_obligations_where_possible(false, |errors| {
+ self.select_obligations_where_possible(|errors| {
self.point_at_return_for_opaque_ty_error(errors, span, return_expr_ty);
});
}
// If the assignment expression itself is ill-formed, don't
// bother emitting another error
- if lhs_ty.references_error() || rhs_ty.references_error() {
- err.delay_as_bug()
- } else {
- err.emit();
- }
- return self.tcx.ty_error();
+ let reported = err.emit_unless(lhs_ty.references_error() || rhs_ty.references_error());
+ return self.tcx.ty_error_with_guaranteed(reported);
}
let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace);
} else {
// Defer other checks until we're done type checking.
let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
- match cast::CastCheck::new(self, e, t_expr, t_cast, t.span, expr.span) {
+ match cast::CastCheck::new(
+ self,
+ e,
+ t_expr,
+ t_cast,
+ t.span,
+ expr.span,
+ self.param_env.constness(),
+ ) {
Ok(cast_check) => {
debug!(
"check_expr_cast: deferring cast from {:?} to {:?}: {:?}",
Some((index_ty, element_ty)) => {
// two-phase not needed because index_ty is never mutable
self.demand_coerce(idx, idx_t, index_ty, None, AllowTwoPhase::No);
- self.select_obligations_where_possible(false, |errors| {
+ self.select_obligations_where_possible(|errors| {
self.point_at_index_if_possible(errors, idx.span)
});
element_ty
);
}
}
- err.emit();
- self.tcx.ty_error()
+ let reported = err.emit();
+ self.tcx.ty_error_with_guaranteed(reported)
}
}
}
use rustc_middle::ty::{self, Ty};
impl<'tcx> FnCtxt<'_, 'tcx> {
- /// Performs type inference fallback, returning true if any fallback
- /// occurs.
- pub(super) fn type_inference_fallback(&self) -> bool {
+ /// Performs type inference fallback, setting `FnCtxt::fallback_has_occurred`
+ /// if fallback has occurred.
+ pub(super) fn type_inference_fallback(&self) {
debug!(
"type-inference-fallback start obligations: {:#?}",
self.fulfillment_cx.borrow_mut().pending_obligations()
);
// All type checking constraints were added, try to fallback unsolved variables.
- self.select_obligations_where_possible(false, |_| {});
+ self.select_obligations_where_possible(|_| {});
debug!(
"type-inference-fallback post selection obligations: {:#?}",
// Check if we have any unsolved variables. If not, no need for fallback.
let unsolved_variables = self.unsolved_variables();
if unsolved_variables.is_empty() {
- return false;
+ return;
}
let diverging_fallback = self.calculate_diverging_fallback(&unsolved_variables);
- let mut fallback_has_occurred = false;
// We do fallback in two passes, to try to generate
// better error messages.
// The first time, we do *not* replace opaque types.
for ty in unsolved_variables {
debug!("unsolved_variable = {:?}", ty);
- fallback_has_occurred |= self.fallback_if_possible(ty, &diverging_fallback);
+ self.fallback_if_possible(ty, &diverging_fallback);
}
// We now see if we can make progress. This might cause us to
// If we had tried to fallback the opaque inference variable to `MyType`,
// we will generate a confusing type-check error that does not explicitly
// refer to opaque types.
- self.select_obligations_where_possible(fallback_has_occurred, |_| {});
-
- fallback_has_occurred
+ self.select_obligations_where_possible(|_| {});
}
// Tries to apply a fallback to `ty` if it is an unsolved variable.
// Fallback becomes very dubious if we have encountered
// type-checking errors. In that case, fallback to Error.
//
- // The return value indicates whether fallback has occurred.
+ // Sets `FnCtxt::fallback_has_occurred` if fallback is performed
+ // during this call.
fn fallback_if_possible(
&self,
ty: Ty<'tcx>,
diverging_fallback: &FxHashMap<Ty<'tcx>, Ty<'tcx>>,
- ) -> bool {
+ ) {
// Careful: we do NOT shallow-resolve `ty`. We know that `ty`
// is an unsolved variable, and we determine its fallback
// based solely on how it was created, not what other type
ty::Infer(ty::FloatVar(_)) => self.tcx.types.f64,
_ => match diverging_fallback.get(&ty) {
Some(&fallback_ty) => fallback_ty,
- None => return false,
+ None => return,
},
};
debug!("fallback_if_possible(ty={:?}): defaulting to `{:?}`", ty, fallback);
.map(|origin| origin.span)
.unwrap_or(rustc_span::DUMMY_SP);
self.demand_eqtype(span, ty, fallback);
- true
+ self.fallback_has_occurred.set(true);
}
/// The "diverging fallback" system is rather complicated. This is
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{
- self, AdtKind, CanonicalUserType, DefIdTree, EarlyBinder, GenericParamDefKind, ToPolyTraitRef,
- ToPredicate, Ty, UserType,
+ self, AdtKind, CanonicalUserType, DefIdTree, EarlyBinder, GenericParamDefKind, ToPredicate, Ty,
+ UserType,
};
use rustc_middle::ty::{GenericArgKind, InternalSubsts, SubstsRef, UserSelfTy, UserSubsts};
use rustc_session::lint;
// possible. This can help substantially when there are
// indirect dependencies that don't seem worth tracking
// precisely.
- self.select_obligations_where_possible(false, mutate_fulfillment_errors);
+ self.select_obligations_where_possible(mutate_fulfillment_errors);
self.resolve_vars_if_possible(ty)
}
self.typeck_results.borrow_mut().node_types_mut().insert(id, ty);
if ty.references_error() {
- self.has_errors.set(true);
self.set_tainted_by_errors();
}
}
pub(in super::super) fn resolve_generator_interiors(&self, def_id: DefId) {
let mut generators = self.deferred_generator_interiors.borrow_mut();
for (body_id, interior, kind) in generators.drain(..) {
- self.select_obligations_where_possible(false, |_| {});
+ self.select_obligations_where_possible(|_| {});
crate::generator_interior::resolve_interior(self, def_id, body_id, interior, kind);
}
}
if !errors.is_empty() {
self.adjust_fulfillment_errors_for_expr_obligation(&mut errors);
- self.err_ctxt().report_fulfillment_errors(&errors, self.inh.body_id, false);
+ self.err_ctxt().report_fulfillment_errors(&errors, self.inh.body_id);
}
}
/// Select as many obligations as we can at present.
pub(in super::super) fn select_obligations_where_possible(
&self,
- fallback_has_occurred: bool,
mutate_fulfillment_errors: impl Fn(&mut Vec<traits::FulfillmentError<'tcx>>),
) {
let mut result = self.fulfillment_cx.borrow_mut().select_where_possible(self);
if !result.is_empty() {
mutate_fulfillment_errors(&mut result);
self.adjust_fulfillment_errors_for_expr_obligation(&mut result);
- self.err_ctxt().report_fulfillment_errors(
- &result,
- self.inh.body_id,
- fallback_has_occurred,
- );
+ self.err_ctxt().report_fulfillment_errors(&result, self.inh.body_id);
}
}
}
#[instrument(skip(self), level = "debug")]
- fn self_type_matches_expected_vid(
- &self,
- trait_ref: ty::PolyTraitRef<'tcx>,
- expected_vid: ty::TyVid,
- ) -> bool {
- let self_ty = self.shallow_resolve(trait_ref.skip_binder().self_ty());
+ fn self_type_matches_expected_vid(&self, self_ty: Ty<'tcx>, expected_vid: ty::TyVid) -> bool {
+ let self_ty = self.shallow_resolve(self_ty);
debug!(?self_ty);
match *self_ty.kind() {
pub(in super::super) fn obligations_for_self_ty<'b>(
&'b self,
self_ty: ty::TyVid,
- ) -> impl Iterator<Item = (ty::PolyTraitRef<'tcx>, traits::PredicateObligation<'tcx>)>
- + Captures<'tcx>
- + 'b {
+ ) -> impl DoubleEndedIterator<Item = traits::PredicateObligation<'tcx>> + Captures<'tcx> + 'b
+ {
// FIXME: consider using `sub_root_var` here so we
// can see through subtyping.
let ty_var_root = self.root_var(self_ty);
trace!("pending_obligations = {:#?}", self.fulfillment_cx.borrow().pending_obligations());
- self.fulfillment_cx
- .borrow()
- .pending_obligations()
- .into_iter()
- .filter_map(move |obligation| {
- let bound_predicate = obligation.predicate.kind();
- match bound_predicate.skip_binder() {
- ty::PredicateKind::Projection(data) => Some((
- bound_predicate.rebind(data).required_poly_trait_ref(self.tcx),
- obligation,
- )),
- ty::PredicateKind::Trait(data) => {
- Some((bound_predicate.rebind(data).to_poly_trait_ref(), obligation))
- }
- ty::PredicateKind::Subtype(..) => None,
- ty::PredicateKind::Coerce(..) => None,
- ty::PredicateKind::RegionOutlives(..) => None,
- ty::PredicateKind::TypeOutlives(..) => None,
- ty::PredicateKind::WellFormed(..) => None,
- ty::PredicateKind::ObjectSafe(..) => None,
- ty::PredicateKind::ConstEvaluatable(..) => None,
- ty::PredicateKind::ConstEquate(..) => None,
- // N.B., this predicate is created by breaking down a
- // `ClosureType: FnFoo()` predicate, where
- // `ClosureType` represents some `Closure`. It can't
- // possibly be referring to the current closure,
- // because we haven't produced the `Closure` for
- // this closure yet; this is exactly why the other
- // code is looking for a self type of an unresolved
- // inference variable.
- ty::PredicateKind::ClosureKind(..) => None,
- ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
+ self.fulfillment_cx.borrow().pending_obligations().into_iter().filter_map(
+ move |obligation| match &obligation.predicate.kind().skip_binder() {
+ ty::PredicateKind::Projection(data)
+ if self.self_type_matches_expected_vid(
+ data.projection_ty.self_ty(),
+ ty_var_root,
+ ) =>
+ {
+ Some(obligation)
}
- })
- .filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root))
+ ty::PredicateKind::Trait(data)
+ if self.self_type_matches_expected_vid(data.self_ty(), ty_var_root) =>
+ {
+ Some(obligation)
+ }
+
+ ty::PredicateKind::Trait(..)
+ | ty::PredicateKind::Projection(..)
+ | ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::Coerce(..)
+ | ty::PredicateKind::RegionOutlives(..)
+ | ty::PredicateKind::TypeOutlives(..)
+ | ty::PredicateKind::WellFormed(..)
+ | ty::PredicateKind::ObjectSafe(..)
+ | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::ConstEquate(..)
+ // N.B., this predicate is created by breaking down a
+ // `ClosureType: FnFoo()` predicate, where
+ // `ClosureType` represents some `Closure`. It can't
+ // possibly be referring to the current closure,
+ // because we haven't produced the `Closure` for
+ // this closure yet; this is exactly why the other
+ // code is looking for a self type of an unresolved
+ // inference variable.
+ | ty::PredicateKind::ClosureKind(..)
+ | ty::PredicateKind::TypeWellFormedFromEnv(..) => None,
+ },
+ )
}
pub(in super::super) fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool {
- self.obligations_for_self_ty(self_ty)
- .any(|(tr, _)| Some(tr.def_id()) == self.tcx.lang_items().sized_trait())
+ let sized_did = self.tcx.lang_items().sized_trait();
+ self.obligations_for_self_ty(self_ty).any(|obligation| {
+ match obligation.predicate.kind().skip_binder() {
+ ty::PredicateKind::Trait(data) => Some(data.def_id()) == sized_did,
+ _ => false,
+ }
+ })
}
pub(in super::super) fn err_args(&self, len: usize) -> Vec<Ty<'tcx>> {
}
}
}
- err.emit();
-
- return (tcx.ty_error(), res);
+ let reported = err.emit();
+ return (tcx.ty_error_with_guaranteed(reported), res);
}
}
} else {
use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext};
use std::iter;
+use std::mem;
use std::ops::ControlFlow;
use std::slice;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
- pub(in super::super) fn check_casts(&self) {
- let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut();
+ pub(in super::super) fn check_casts(&mut self) {
+ // don't hold the borrow to deferred_cast_checks while checking to avoid borrow checker errors
+ // when writing to `self.param_env`.
+ let mut deferred_cast_checks = mem::take(&mut *self.deferred_cast_checks.borrow_mut());
+
debug!("FnCtxt::check_casts: {} deferred checks", deferred_cast_checks.len());
for cast in deferred_cast_checks.drain(..) {
+ let prev_env = self.param_env;
+ self.param_env = self.param_env.with_constness(cast.constness);
+
cast.check(self);
+
+ self.param_env = prev_env;
}
+
+ *self.deferred_cast_checks.borrow_mut() = deferred_cast_checks;
}
pub(in super::super) fn check_transmutes(&self) {
tuple_arguments,
Some(method.def_id),
);
+
method.sig.output()
}
"cannot use call notation; the first type parameter \
for the function trait is neither a tuple nor unit"
)
- .emit();
+ .delay_as_bug();
(self.err_args(provided_args.len()), None)
}
}
// an "opportunistic" trait resolution of any trait bounds on
// the call. This helps coercions.
if check_closures {
- self.select_obligations_where_possible(false, |_| {})
+ self.select_obligations_where_possible(|_| {})
}
// Check each argument, to satisfy the input it was provided for
// Hide the outer diverging and `has_errors` flags.
let old_diverges = self.diverges.replace(Diverges::Maybe);
- let old_has_errors = self.has_errors.replace(false);
match stmt.kind {
hir::StmtKind::Local(l) => {
// Combine the diverging and `has_error` flags.
self.diverges.set(self.diverges.get() | old_diverges);
- self.has_errors.set(self.has_errors.get() | old_has_errors);
}
pub fn check_block_no_value(&self, blk: &'tcx hir::Block<'tcx>) {
self.diverges.set(prev_diverges);
}
- let mut ty = ctxt.coerce.unwrap().complete(self);
-
- if self.has_errors.get() || ty.references_error() {
- ty = self.tcx.ty_error()
- }
+ let ty = ctxt.coerce.unwrap().complete(self);
self.write_ty(blk.hir_id, ty);
/// any).
pub(super) ret_coercion: Option<RefCell<DynamicCoerceMany<'tcx>>>,
- /// Used exclusively to reduce cost of advanced evaluation used for
- /// more helpful diagnostics.
- pub(super) in_tail_expr: bool,
-
/// First span of a return site that we find. Used in error messages.
pub(super) ret_coercion_span: Cell<Option<Span>>,
/// the diverges flag is set to something other than `Maybe`.
pub(super) diverges: Cell<Diverges>,
- /// Whether any child nodes have any type errors.
- pub(super) has_errors: Cell<bool>,
-
pub(super) enclosing_breakables: RefCell<EnclosingBreakables<'tcx>>,
pub(super) inh: &'a Inherited<'tcx>,
- /// True if the function or closure's return type is known before
- /// entering the function/closure, i.e. if the return type is
- /// either given explicitly or inferred from, say, an `Fn*` trait
- /// bound. Used for diagnostic purposes only.
- pub(super) return_type_pre_known: bool,
-
- /// True if the return type has an Opaque type
- pub(super) return_type_has_opaque: bool,
+ pub(super) fallback_has_occurred: Cell<bool>,
}
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
param_env,
err_count_on_creation: inh.tcx.sess.err_count(),
ret_coercion: None,
- in_tail_expr: false,
ret_coercion_span: Cell::new(None),
resume_yield_tys: None,
ps: Cell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)),
diverges: Cell::new(Diverges::Maybe),
- has_errors: Cell::new(false),
enclosing_breakables: RefCell::new(EnclosingBreakables {
stack: Vec::new(),
by_id: Default::default(),
}),
inh,
- return_type_pre_known: true,
- return_type_has_opaque: false,
+ fallback_has_occurred: Cell::new(false),
}
}
///
/// [`InferCtxt::err_ctxt`]: infer::InferCtxt::err_ctxt
pub fn err_ctxt(&'a self) -> TypeErrCtxt<'a, 'tcx> {
- TypeErrCtxt { infcx: &self.infcx, typeck_results: Some(self.typeck_results.borrow()) }
+ TypeErrCtxt {
+ infcx: &self.infcx,
+ typeck_results: Some(self.typeck_results.borrow()),
+ fallback_has_occurred: self.fallback_has_occurred.get(),
+ }
}
pub fn errors_reported_since_creation(&self) -> bool {
self.tcx
}
- fn item_def_id(&self) -> Option<DefId> {
- None
+ fn item_def_id(&self) -> DefId {
+ self.body_id.owner.to_def_id()
}
fn get_type_parameter_bounds(
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+ pub(crate) fn body_fn_sig(&self) -> Option<ty::FnSig<'tcx>> {
+ self.typeck_results
+ .borrow()
+ .liberated_fn_sigs()
+ .get(self.tcx.hir().get_parent_node(self.body_id))
+ .copied()
+ }
+
pub(in super::super) fn suggest_semicolon_at_end(&self, span: Span, err: &mut Diagnostic) {
err.span_suggestion_short(
span.shrink_to_hi(),
use rustc_hir::hir_id::HirIdSet;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Arm, Expr, ExprKind, Guard, HirId, Pat, PatKind};
+use rustc_infer::infer::RegionVariableOrigin;
use rustc_middle::middle::region::{self, Scope, ScopeData, YieldData};
-use rustc_middle::ty::{self, RvalueScopes, Ty, TyCtxt, TypeVisitable};
+use rustc_middle::ty::fold::FnMutDelegate;
+use rustc_middle::ty::{self, BoundVariableKind, RvalueScopes, Ty, TyCtxt, TypeVisitable};
use rustc_span::symbol::sym;
use rustc_span::Span;
+use smallvec::{smallvec, SmallVec};
mod drop_ranges;
debug!("types in generator {:?}, span = {:?}", types, body.value.span);
- let mut counter = 0;
+ // We want to deduplicate if the lifetimes are the same modulo some non-informative counter.
+ // So, we need to actually do two passes: first by type to anonymize (preserving information
+ // required for diagnostics), then a second pass over all captured types to reassign disjoint
+ // region indices.
let mut captured_tys = FxHashSet::default();
let type_causes: Vec<_> = types
.into_iter()
.filter_map(|mut cause| {
- // Erase regions and canonicalize late-bound regions to deduplicate as many types as we
- // can.
+ // Replace all regions inside the generator interior with late bound regions.
+ // Note that each region slot in the types gets a new fresh late bound region,
+ // which means that none of the regions inside relate to any other, even if
+ // typeck had previously found constraints that would cause them to be related.
+
+ let mut counter = 0;
+ let mut mk_bound_region = |span| {
+ let kind = ty::BrAnon(counter, span);
+ let var = ty::BoundVar::from_u32(counter);
+ counter += 1;
+ ty::BoundRegion { var, kind }
+ };
let ty = fcx.normalize_associated_types_in(cause.span, cause.ty);
- let erased = fcx.tcx.erase_regions(ty);
- if captured_tys.insert(erased) {
- // Replace all regions inside the generator interior with late bound regions.
- // Note that each region slot in the types gets a new fresh late bound region,
- // which means that none of the regions inside relate to any other, even if
- // typeck had previously found constraints that would cause them to be related.
- let folded = fcx.tcx.fold_regions(erased, |_, current_depth| {
- let br = ty::BoundRegion {
- var: ty::BoundVar::from_u32(counter),
- kind: ty::BrAnon(counter),
- };
- let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, br));
- counter += 1;
- r
- });
-
- cause.ty = folded;
+ let ty = fcx.tcx.fold_regions(ty, |region, current_depth| {
+ let br = match region.kind() {
+ ty::ReVar(vid) => {
+ let origin = fcx.region_var_origin(vid);
+ match origin {
+ RegionVariableOrigin::EarlyBoundRegion(span, _) => {
+ mk_bound_region(Some(span))
+ }
+ _ => mk_bound_region(None),
+ }
+ }
+ // FIXME: these should use `BrNamed`
+ ty::ReEarlyBound(region) => {
+ mk_bound_region(Some(fcx.tcx.def_span(region.def_id)))
+ }
+ ty::ReLateBound(_, ty::BoundRegion { kind, .. })
+ | ty::ReFree(ty::FreeRegion { bound_region: kind, .. }) => match kind {
+ ty::BoundRegionKind::BrAnon(_, span) => mk_bound_region(span),
+ ty::BoundRegionKind::BrNamed(def_id, _) => {
+ mk_bound_region(Some(fcx.tcx.def_span(def_id)))
+ }
+ ty::BoundRegionKind::BrEnv => mk_bound_region(None),
+ },
+ _ => mk_bound_region(None),
+ };
+ let r = fcx.tcx.mk_region(ty::ReLateBound(current_depth, br));
+ r
+ });
+ if captured_tys.insert(ty) {
+ cause.ty = ty;
Some(cause)
} else {
None
})
.collect();
+ let mut bound_vars: SmallVec<[BoundVariableKind; 4]> = smallvec![];
+ let mut counter = 0;
+ // Optimization: If there is only one captured type, then we don't actually
+ // need to fold and reindex (since the first type doesn't change).
+ let type_causes = if captured_tys.len() > 0 {
+ // Optimization: Use `replace_escaping_bound_vars_uncached` instead of
+ // `fold_regions`, since we only have late bound regions, and it skips
+ // types without bound regions.
+ fcx.tcx.replace_escaping_bound_vars_uncached(
+ type_causes,
+ FnMutDelegate {
+ regions: &mut |br| {
+ let kind = match br.kind {
+ ty::BrAnon(_, span) => ty::BrAnon(counter, span),
+ _ => br.kind,
+ };
+ let var = ty::BoundVar::from_usize(bound_vars.len());
+ bound_vars.push(ty::BoundVariableKind::Region(kind));
+ counter += 1;
+ fcx.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BoundRegion { var, kind }))
+ },
+ types: &mut |b| bug!("unexpected bound ty in binder: {b:?}"),
+ consts: &mut |b, ty| bug!("unexpected bound ct in binder: {b:?} {ty}"),
+ },
+ )
+ } else {
+ type_causes
+ };
+
// Extract type components to build the witness type.
let type_list = fcx.tcx.mk_type_list(type_causes.iter().map(|cause| cause.ty));
- let bound_vars = fcx.tcx.mk_bound_variable_kinds(
- (0..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i))),
- );
+ let bound_vars = fcx.tcx.mk_bound_variable_kinds(bound_vars.iter());
let witness =
fcx.tcx.mk_generator_witness(ty::Binder::bind_with_vars(type_list, bound_vars.clone()));
use crate::check::check_fn;
use crate::coercion::DynamicCoerceMany;
use crate::gather_locals::GatherLocalsVisitor;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::unord::UnordSet;
use rustc_errors::{struct_span_err, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def::Res;
}
}
-fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet<LocalDefId> {
+fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &UnordSet<LocalDefId> {
&*tcx.typeck(def_id).used_trait_imports
}
typeck_with_fallback(tcx, def_id, fallback)
}
+#[instrument(level = "debug", skip(tcx, fallback), ret)]
fn typeck_with_fallback<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
param_env,
fn_sig,
);
- check_fn(&inh, param_env, fn_sig, decl, id, body, None, true).0
+ check_fn(&inh, param_env, fn_sig, decl, id, body, None).0
} else {
let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id);
let expected_type = body_ty
fcx
};
- let fallback_has_occurred = fcx.type_inference_fallback();
+ fcx.type_inference_fallback();
// Even though coercion casts provide type hints, we check casts after fallback for
// backwards compatibility. This makes fallback a stronger type hint than a cast coercion.
fcx.check_casts();
- fcx.select_obligations_where_possible(fallback_has_occurred, |_| {});
+ fcx.select_obligations_where_possible(|_| {});
// Closure and generator analysis may run after fallback
// because they don't constrain other type variables.
/// # fn f(x: (isize, isize)) {}
/// f((1, 2));
/// ```
-#[derive(Clone, Eq, PartialEq)]
+#[derive(Copy, Clone, Eq, PartialEq)]
enum TupleArgumentsFlag {
DontTupleArguments,
TupleArguments,
// not-in-scope traits which may work.
PrivateMatch(DefKind, DefId, Vec<DefId>),
- // Found a `Self: Sized` bound where `Self` is a trait object, also the caller may have
- // forgotten to import a trait.
+ // Found a `Self: Sized` bound where `Self` is a trait object.
IllegalSizedBound(Vec<DefId>, bool, Span),
// Found a match, but the return type is wrong
/// would result in an error (basically, the same criteria we
/// would use to decide if a method is a plausible fit for
/// ambiguity purposes).
- #[instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self, candidate_filter))]
pub fn probe_for_return_type(
&self,
span: Span,
return_type: Ty<'tcx>,
self_ty: Ty<'tcx>,
scope_expr_id: hir::HirId,
+ candidate_filter: impl Fn(&ty::AssocItem) -> bool,
) -> Vec<ty::AssocItem> {
let method_names = self
.probe_op(
self_ty,
scope_expr_id,
ProbeScope::AllTraits,
- |probe_cx| Ok(probe_cx.candidate_method_names()),
+ |probe_cx| Ok(probe_cx.candidate_method_names(candidate_filter)),
)
.unwrap_or_default();
method_names
}
}
- fn candidate_method_names(&self) -> Vec<Ident> {
+ fn candidate_method_names(
+ &self,
+ candidate_filter: impl Fn(&ty::AssocItem) -> bool,
+ ) -> Vec<Ident> {
let mut set = FxHashSet::default();
let mut names: Vec<_> = self
.inherent_candidates
.iter()
.chain(&self.extension_candidates)
+ .filter(|candidate| candidate_filter(&candidate.item))
.filter(|candidate| {
if let Some(return_ty) = self.return_type {
self.matches_return_type(&candidate.item, None, return_ty)
let out_of_scope_traits = match self.pick_core() {
Some(Ok(p)) => vec![p.item.container_id(self.tcx)],
- //Some(Ok(p)) => p.iter().map(|p| p.item.container().id()).collect(),
Some(Err(MethodError::Ambiguity(v))) => v
.into_iter()
.map(|source| match source {
pcx.allow_similar_names = true;
pcx.assemble_inherent_candidates();
- let method_names = pcx.candidate_method_names();
+ let method_names = pcx.candidate_method_names(|_| true);
pcx.allow_similar_names = false;
let applicable_close_candidates: Vec<ty::AssocItem> = method_names
.iter()
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Symbol;
use rustc_span::{lev_distance, source_map, ExpnKind, FileName, MacroKind, Span};
+use rustc_trait_selection::traits::error_reporting::on_unimplemented::OnUnimplementedNote;
use rustc_trait_selection::traits::error_reporting::on_unimplemented::TypeErrCtxtExt as _;
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_trait_selection::traits::{
- FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedNote,
+ FulfillmentError, Obligation, ObligationCause, ObligationCauseCode,
};
use std::cmp::Ordering;
let report_candidates = |span: Span,
err: &mut Diagnostic,
- mut sources: Vec<CandidateSource>,
+ sources: &mut Vec<CandidateSource>,
sugg_span: Span| {
sources.sort();
sources.dedup();
match error {
MethodError::NoMatch(NoMatchData {
- static_candidates: static_sources,
+ mut static_candidates,
unsatisfied_predicates,
out_of_scope_traits,
lev_candidate,
if generics.len() > 0 {
let mut autoderef = self.autoderef(span, actual);
let candidate_found = autoderef.any(|(ty, _)| {
- if let ty::Adt(adt_deref, _) = ty.kind() {
+ if let ty::Adt(adt_def, _) = ty.kind() {
self.tcx
- .inherent_impls(adt_deref.did())
+ .inherent_impls(adt_def.did())
.iter()
.filter_map(|def_id| self.associated_value(*def_id, item_name))
.count()
}
let ty_span = match actual.kind() {
- ty::Param(param_type) => {
- let generics = self.tcx.generics_of(self.body_id.owner.to_def_id());
- let type_param = generics.type_param(param_type, self.tcx);
- Some(self.tcx.def_span(type_param.def_id))
- }
+ ty::Param(param_type) => Some(
+ param_type.span_from_generics(self.tcx, self.body_id.owner.to_def_id()),
+ ),
ty::Adt(def, _) if def.did().is_local() => Some(tcx.def_span(def.did())),
_ => None,
};
-
if let Some(span) = ty_span {
err.span_label(
span,
let mut custom_span_label = false;
- if !static_sources.is_empty() {
+ if !static_candidates.is_empty() {
err.note(
"found the following associated functions; to be used as methods, \
functions must have a `self` parameter",
err.span_label(span, "this is an associated function, not a method");
custom_span_label = true;
}
- if static_sources.len() == 1 {
+ if static_candidates.len() == 1 {
let ty_str =
- if let Some(CandidateSource::Impl(impl_did)) = static_sources.get(0) {
+ if let Some(CandidateSource::Impl(impl_did)) = static_candidates.get(0) {
// When the "method" is resolved through dereferencing, we really want the
// original type that has the associated function for accurate suggestions.
// (#61411)
err.help(&format!("try with `{}::{}`", ty_str, item_name,));
}
- report_candidates(span, &mut err, static_sources, sugg_span);
- } else if static_sources.len() > 1 {
- report_candidates(span, &mut err, static_sources, sugg_span);
+ report_candidates(span, &mut err, &mut static_candidates, sugg_span);
+ } else if static_candidates.len() > 1 {
+ report_candidates(span, &mut err, &mut static_candidates, sugg_span);
}
let mut bound_spans = vec![];
if let (ty::Param(_), ty::PredicateKind::Trait(p)) =
(self_ty.kind(), parent_pred.kind().skip_binder())
{
+ let hir = self.tcx.hir();
let node = match p.trait_ref.self_ty().kind() {
ty::Param(_) => {
// Account for `fn` items like in `issue-35677.rs` to
// suggest restricting its type params.
- let did = self.tcx.hir().body_owner_def_id(hir::BodyId {
- hir_id: self.body_id,
- });
- Some(
- self.tcx
- .hir()
- .get(self.tcx.hir().local_def_id_to_hir_id(did)),
- )
+ let parent_body =
+ hir.body_owner(hir::BodyId { hir_id: self.body_id });
+ Some(hir.get(parent_body))
+ }
+ ty::Adt(def, _) => {
+ def.did().as_local().map(|def_id| hir.get_by_def_id(def_id))
}
- ty::Adt(def, _) => def.did().as_local().map(|def_id| {
- self.tcx
- .hir()
- .get(self.tcx.hir().local_def_id_to_hir_id(def_id))
- }),
_ => None,
};
if let Some(hir::Node::Item(hir::Item { kind, .. })) = node {
.iter()
.filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c)))
.filter_map(|(p, parent, c)| match c.code() {
- ObligationCauseCode::ImplDerivedObligation(ref data) => {
+ ObligationCauseCode::ImplDerivedObligation(data) => {
Some((&data.derived, p, parent, data.impl_def_id, data))
}
_ => None,
match self.tcx.hir().get_if_local(impl_def_id) {
// Unmet obligation comes from a `derive` macro, point at it once to
// avoid multiple span labels pointing at the same place.
- Some(Node::Item(hir::Item {
- kind: hir::ItemKind::Trait(..),
- ident,
- ..
- })) if matches!(
- ident.span.ctxt().outer_expn_data().kind,
- ExpnKind::Macro(MacroKind::Derive, _)
- ) =>
- {
- let span = ident.span.ctxt().outer_expn_data().call_site;
- let mut spans: MultiSpan = span.into();
- spans.push_span_label(span, derive_msg);
- let entry = spanned_predicates.entry(spans);
- entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
- }
-
Some(Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
..
entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
}
- // Unmet obligation coming from a `trait`.
- Some(Node::Item(hir::Item {
- kind: hir::ItemKind::Trait(..),
- ident,
- span: item_span,
- ..
- })) if !matches!(
- ident.span.ctxt().outer_expn_data().kind,
- ExpnKind::Macro(MacroKind::Derive, _)
- ) =>
- {
- if let Some(pred) = parent_p {
- // Done to add the "doesn't satisfy" `span_label`.
- let _ = format_pred(*pred);
- }
- skip_list.insert(p);
- let mut spans = if cause.span != *item_span {
- let mut spans: MultiSpan = cause.span.into();
- spans.push_span_label(cause.span, unsatisfied_msg);
- spans
- } else {
- ident.span.into()
- };
- spans.push_span_label(ident.span, "in this trait");
- let entry = spanned_predicates.entry(spans);
- entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
- }
-
// Unmet obligation coming from an `impl`.
Some(Node::Item(hir::Item {
kind:
}),
span: item_span,
..
- })) if !matches!(
- self_ty.span.ctxt().outer_expn_data().kind,
- ExpnKind::Macro(MacroKind::Derive, _)
- ) && !matches!(
- of_trait.as_ref().map(|t| t
- .path
- .span
- .ctxt()
- .outer_expn_data()
- .kind),
- Some(ExpnKind::Macro(MacroKind::Derive, _))
- ) =>
- {
+ })) => {
let sized_pred =
unsatisfied_predicates.iter().any(|(pred, _, _)| {
match pred.kind().skip_binder() {
let entry = spanned_predicates.entry(spans);
entry.or_insert_with(|| (path, tr_self_ty, Vec::new())).2.push(p);
}
- _ => {}
+ Some(_) => unreachable!(),
+ None => (),
}
}
let mut spanned_predicates: Vec<_> = spanned_predicates.into_iter().collect();
.on_unimplemented_note(trait_ref, &obligation);
(message, label)
})
- .unwrap_or((None, None))
+ .unwrap()
} else {
(None, None)
};
// If the method name is the name of a field with a function or closure type,
// give a helping note that it has to be called as `(x.f)(...)`.
if let SelfSource::MethodCall(expr) = source {
- if !self.suggest_field_call(span, rcvr_ty, expr, item_name, &mut err)
+ if !self.suggest_calling_field_as_fn(span, rcvr_ty, expr, item_name, &mut err)
&& lev_candidate.is_none()
&& !custom_span_label
{
label_span_not_found(&mut err);
}
- // Don't suggest (for example) `expr.field.method()` if `expr.method()`
- // doesn't exist due to unsatisfied predicates.
+ // Don't suggest (for example) `expr.field.clone()` if `expr.clone()`
+ // can't be called due to `typeof(expr): Clone` not holding.
if unsatisfied_predicates.is_empty() {
- self.check_for_field_method(&mut err, source, span, actual, item_name);
+ self.suggest_calling_method_on_field(&mut err, source, span, actual, item_name);
}
self.check_for_inner_self(&mut err, source, span, actual, item_name);
source,
out_of_scope_traits,
&unsatisfied_predicates,
+ &static_candidates,
unsatisfied_bounds,
);
}
return Some(err);
}
- MethodError::Ambiguity(sources) => {
+ MethodError::Ambiguity(mut sources) => {
let mut err = struct_span_err!(
self.sess(),
item_name.span,
);
err.span_label(item_name.span, format!("multiple `{}` found", item_name));
- report_candidates(span, &mut err, sources, sugg_span);
+ report_candidates(span, &mut err, &mut sources, sugg_span);
err.emit();
}
None
}
- fn suggest_field_call(
+ /// Suggest calling a field with a type that implements the `Fn*` traits instead of a method with
+ /// the same name as the field i.e. `(a.my_fn_ptr)(10)` instead of `a.my_fn_ptr(10)`.
+ fn suggest_calling_field_as_fn(
&self,
span: Span,
rcvr_ty: Ty<'tcx>,
false
}
- fn check_for_field_method(
+ /// Suggest calling a method on a field i.e. `a.field.bar()` instead of `a.bar()`
+ fn suggest_calling_method_on_field(
&self,
err: &mut Diagnostic,
source: SelfSource<'tcx>,
Option<ty::Predicate<'tcx>>,
Option<ObligationCause<'tcx>>,
)],
+ static_candidates: &[CandidateSource],
unsatisfied_bounds: bool,
) {
let mut alt_rcvr_sugg = false;
if let (SelfSource::MethodCall(rcvr), false) = (source, unsatisfied_bounds) {
- debug!(?span, ?item_name, ?rcvr_ty, ?rcvr);
+ debug!(
+ "suggest_traits_to_import: span={:?}, item_name={:?}, rcvr_ty={:?}, rcvr={:?}",
+ span, item_name, rcvr_ty, rcvr
+ );
let skippable = [
self.tcx.lang_items().clone_trait(),
self.tcx.lang_items().deref_trait(),
// suggestions are generally misleading (see #94218).
break;
}
- _ => {}
+ Err(_) => (),
}
for (rcvr_ty, pre) in &[
Some(attr) => attr.level.is_stable(),
None => true,
})
+ .filter(|info| {
+ // Static candidates are already implemented, and known not to work
+ // Do not suggest them again
+ static_candidates.iter().all(|sc| match *sc {
+ CandidateSource::Trait(def_id) => def_id != info.def_id,
+ CandidateSource::Impl(def_id) => {
+ self.tcx.trait_id_of_impl(def_id) != Some(info.def_id)
+ }
+ })
+ })
.filter(|info| {
// We approximate the coherence rules to only suggest
// traits that are legal to implement by requiring that
use rustc_span::Span;
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
-use rustc_trait_selection::traits::{FulfillmentError, TraitEngine, TraitEngineExt};
+use rustc_trait_selection::traits::FulfillmentError;
use rustc_type_ir::sty::TyKind::*;
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
}
- err.emit();
- self.tcx.ty_error()
+ let reported = err.emit();
+ self.tcx.ty_error_with_guaranteed(reported)
}
};
match (method, trait_did) {
(Some(ok), _) => {
let method = self.register_infer_ok_obligations(ok);
- self.select_obligations_where_possible(false, |_| {});
+ self.select_obligations_where_possible(|_| {});
Ok(method)
}
(None, None) => Err(vec![]),
other_ty_expr,
expected,
);
- let mut fulfill = <dyn TraitEngine<'_>>::new(self.tcx);
- fulfill.register_predicate_obligation(self, obligation);
- Err(fulfill.select_where_possible(&self.infcx))
+ Err(rustc_trait_selection::traits::fully_solve_obligation(self, obligation))
}
}
}
let element_tys = tcx.mk_type_list(element_tys_iter);
let pat_ty = tcx.mk_ty(ty::Tuple(element_tys));
if let Some(mut err) = self.demand_eqtype_pat_diag(span, expected, pat_ty, ti) {
- err.emit();
+ let reported = err.emit();
// Walk subpatterns with an expected type of `err` in this case to silence
// further errors being emitted when using the bindings. #50333
- let element_tys_iter = (0..max_len).map(|_| tcx.ty_error());
+ let element_tys_iter = (0..max_len).map(|_| tcx.ty_error_with_guaranteed(reported));
for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
- self.check_pat(elem, tcx.ty_error(), def_bm, ti);
+ self.check_pat(elem, tcx.ty_error_with_guaranteed(reported), def_bm, ti);
}
tcx.mk_tup(element_tys_iter)
} else {
Applicability::MachineApplicable,
);
}
- err.emit();
- Some((self.tcx.ty_error(), self.tcx.ty_error()))
+ let reported = err.emit();
+ Some((
+ self.tcx.ty_error_with_guaranteed(reported),
+ self.tcx.ty_error_with_guaranteed(reported),
+ ))
}
/// To type-check `base_expr[index_expr]`, we progressively autoderef
let crate_items = tcx.hir_crate_items(());
for id in crate_items.items() {
- dirty_clean_visitor.check_item(id.def_id.def_id);
+ dirty_clean_visitor.check_item(id.owner_id.def_id);
}
for id in crate_items.trait_items() {
- dirty_clean_visitor.check_item(id.def_id.def_id);
+ dirty_clean_visitor.check_item(id.owner_id.def_id);
}
for id in crate_items.impl_items() {
- dirty_clean_visitor.check_item(id.def_id.def_id);
+ dirty_clean_visitor.check_item(id.owner_id.def_id);
}
for id in crate_items.foreign_items() {
- dirty_clean_visitor.check_item(id.def_id.def_id);
+ dirty_clean_visitor.check_item(id.owner_id.def_id);
}
let mut all_attrs = FindAllAttrs { tcx, found_attrs: vec![] };
#[derive(Subdiagnostic)]
pub enum SourceKindSubdiag<'a> {
- #[suggestion_verbose(
+ #[suggestion(
infer_source_kind_subdiag_let,
+ style = "verbose",
code = ": {type_name}",
applicability = "has-placeholders"
)]
parent_prefix: String,
parent_name: String,
},
- #[suggestion_verbose(
+ #[suggestion(
infer_source_kind_subdiag_generic_suggestion,
+ style = "verbose",
code = "::<{args}>",
applicability = "has-placeholders"
)]
#[derive(Subdiagnostic)]
pub enum SourceKindMultiSuggestion<'a> {
- #[multipart_suggestion_verbose(
+ #[multipart_suggestion(
infer_source_kind_fully_qualified,
+ style = "verbose",
applicability = "has-placeholders"
)]
FullyQualified {
adjustment: &'a str,
successor_pos: &'a str,
},
- #[multipart_suggestion_verbose(
+ #[multipart_suggestion(
infer_source_kind_closure_return,
+ style = "verbose",
applicability = "has-placeholders"
)]
ClosureReturn {
#[primary_span]
span: Span,
},
- #[suggestion_verbose(
+ #[suggestion(
infer_implicit_static_lifetime_suggestion,
+ style = "verbose",
code = " + '_",
applicability = "maybe-incorrect"
)]
};
me.span = Some(sp);
}
- ty::BrAnon(idx) => {
+ ty::BrAnon(idx, span) => {
me.kind = "anon_num_here";
me.num_arg = idx+1;
- me.span = Some(tcx.def_span(scope));
+ me.span = match span {
+ Some(_) => span,
+ None => Some(tcx.def_span(scope)),
+ }
},
_ => {
me.kind = "defined_here_reg";
}
ty::ConstKind::Bound(debruijn, _) => {
if debruijn >= self.binder_index {
- bug!("escaping bound type during canonicalization")
+ bug!("escaping bound const during canonicalization")
} else {
return ct;
}
r: ty::Region<'tcx>,
) -> ty::Region<'tcx> {
let var = self.canonical_var(info, r.into());
- let br = ty::BoundRegion { var, kind: ty::BrAnon(var.as_u32()) };
+ let br = ty::BoundRegion { var, kind: ty::BrAnon(var.as_u32(), None) };
let region = ty::ReLateBound(self.binder_index, br);
self.tcx().mk_region(region)
}
self.fold_const(bound_to)
} else {
let var = self.canonical_var(info, const_var.into());
- self.tcx().mk_const(ty::ConstS {
- kind: ty::ConstKind::Bound(self.binder_index, var),
- ty: self.fold_ty(const_var.ty()),
- })
+ self.tcx().mk_const(
+ ty::ConstKind::Bound(self.binder_index, var),
+ self.fold_ty(const_var.ty()),
+ )
}
}
}
///
/// This is only meant to be invoked as part of constructing an
/// inference context at the start of a query (see
- /// `InferCtxtBuilder::enter_with_canonical`). It basically
+ /// `InferCtxtBuilder::build_with_canonical`). It basically
/// brings the canonical value "into scope" within your new infcx.
///
/// At the end of processing, the substitution S (once
CanonicalVarKind::PlaceholderConst(ty::PlaceholderConst { universe, name }, ty) => {
let universe_mapped = universe_map(universe);
let placeholder_mapped = ty::PlaceholderConst { universe: universe_mapped, name };
- self.tcx
- .mk_const(ty::ConstS {
- kind: ty::ConstKind::Placeholder(placeholder_mapped),
- ty,
- })
- .into()
+ self.tcx.mk_const(ty::ConstKind::Placeholder(placeholder_mapped), ty).into()
}
}
}
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
use crate::infer::{InferCtxt, InferOk, InferResult, NllRegionVariableOrigin};
use crate::traits::query::{Fallible, NoSolution};
-use crate::traits::TraitEngine;
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
+use crate::traits::{PredicateObligations, TraitEngine};
use rustc_data_structures::captures::Captures;
use rustc_index::vec::Idx;
use rustc_index::vec::IndexVec;
for &(a, b) in &query_response.value.opaque_types {
let a = substitute_value(self.tcx, &result_subst, a);
let b = substitute_value(self.tcx, &result_subst, b);
- obligations.extend(self.handle_opaque_type(a, b, true, cause, param_env)?.obligations);
+ obligations.extend(self.at(cause, param_env).eq(a, b)?.obligations);
}
Ok(InferOk { value: result_subst, obligations })
/// creates query region constraints.
pub fn make_query_region_constraints<'tcx>(
tcx: TyCtxt<'tcx>,
- outlives_obligations: impl Iterator<Item = (Ty<'tcx>, ty::Region<'tcx>, ConstraintCategory)>,
+ outlives_obligations: impl Iterator<Item = (Ty<'tcx>, ty::Region<'tcx>, ConstraintCategory<'tcx>)>,
region_constraints: &RegionConstraintData<'tcx>,
) -> QueryRegionConstraints<'tcx> {
let RegionConstraintData { constraints, verifys, givens, member_constraints } =
true
}
- fn register_opaque_type(
+ fn register_opaque_type_obligations(
&mut self,
- a: Ty<'tcx>,
- b: Ty<'tcx>,
- a_is_expected: bool,
+ obligations: PredicateObligations<'tcx>,
) -> Result<(), TypeError<'tcx>> {
- self.obligations.extend(
- self.infcx
- .handle_opaque_type(a, b, a_is_expected, &self.cause, self.param_env)?
- .obligations,
- );
+ self.obligations.extend(obligations);
Ok(())
}
}
substs,
substs,
)?;
- Ok(self.tcx().mk_const(ty::ConstS {
- ty: c.ty(),
- kind: ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }),
- }))
+ Ok(self.tcx().mk_const(
+ ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }),
+ c.ty(),
+ ))
}
_ => relate::super_relate_consts(self, c, c),
}
substs,
)?;
- Ok(self.tcx().mk_const(ty::ConstS {
- ty: c.ty(),
- kind: ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }),
- }))
+ Ok(self.tcx().mk_const(
+ ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }),
+ c.ty(),
+ ))
}
_ => relate::super_relate_consts(self, c, c),
}
StatementAsExpression,
};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed, IntoDiagnosticArg};
use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString, MultiSpan};
use rustc_hir as hir;
pub struct TypeErrCtxt<'a, 'tcx> {
pub infcx: &'a InferCtxt<'tcx>,
pub typeck_results: Option<std::cell::Ref<'a, ty::TypeckResults<'tcx>>>,
+ pub fallback_has_occurred: bool,
}
impl TypeErrCtxt<'_, '_> {
};
(text, sp)
}
- ty::BrAnon(idx) => (
+ ty::BrAnon(idx, span) => (
format!("the anonymous lifetime #{} defined here", idx + 1),
- tcx.def_span(scope)
+ match span {
+ Some(span) => span,
+ None => tcx.def_span(scope)
+ }
),
_ => (
format!("the lifetime `{}` as defined here", region),
values = None;
}
struct OpaqueTypesVisitor<'tcx> {
- types: FxHashMap<TyCategory, FxHashSet<Span>>,
- expected: FxHashMap<TyCategory, FxHashSet<Span>>,
- found: FxHashMap<TyCategory, FxHashSet<Span>>,
+ types: FxIndexMap<TyCategory, FxIndexSet<Span>>,
+ expected: FxIndexMap<TyCategory, FxIndexSet<Span>>,
+ found: FxIndexMap<TyCategory, FxIndexSet<Span>>,
ignore_span: Span,
tcx: TyCtxt<'tcx>,
}
&self,
err: &mut Diagnostic,
target: &str,
- types: &FxHashMap<TyCategory, FxHashSet<Span>>,
+ types: &FxIndexMap<TyCategory, FxIndexSet<Span>>,
) {
for (key, values) in types.iter() {
let count = values.len();
if blk.expr.is_some() {
return false;
}
- let mut shadowed = FxHashSet::default();
+ let mut shadowed = FxIndexSet::default();
let mut candidate_idents = vec![];
let mut find_compatible_candidates = |pat: &hir::Pat<'_>| {
if let hir::PatKind::Binding(_, hir_id, ident, _) = &pat.kind
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::{SubregionOrigin, TypeTrace};
use crate::traits::ObligationCauseCode;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::intravisit::Visitor;
// Next, let's figure out the set of trait objects with implicit static bounds
let ty = self.tcx().type_of(*impl_def_id);
- let mut v = super::static_impl_trait::TraitObjectVisitor(FxHashSet::default());
+ let mut v = super::static_impl_trait::TraitObjectVisitor(FxIndexSet::default());
v.visit_ty(ty);
let mut traits = vec![];
for matching_def_id in v.0 {
mod mismatched_static_lifetime;
mod named_anon_conflict;
mod placeholder_error;
+mod placeholder_relation;
mod static_impl_trait;
mod trait_impl_difference;
mod util;
pub fn try_report_from_nll(&self) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
// Due to the improved diagnostics returned by the MIR borrow checker, only a subset of
// the nice region errors are required when running under the MIR borrow checker.
- self.try_report_named_anon_conflict().or_else(|| self.try_report_placeholder_conflict())
+ self.try_report_named_anon_conflict()
+ .or_else(|| self.try_report_placeholder_conflict())
+ .or_else(|| self.try_report_placeholder_relation())
}
pub fn try_report(&self) -> Option<ErrorGuaranteed> {
let is_impl_item = region_info.is_impl_item;
match br {
- ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(_) => {}
+ ty::BrNamed(_, kw::UnderscoreLifetime) | ty::BrAnon(..) => {}
_ => {
/* not an anonymous region */
debug!("try_report_named_anon_conflict: not an anonymous region");
--- /dev/null
+use crate::infer::{
+ error_reporting::nice_region_error::NiceRegionError, RegionResolutionError, SubregionOrigin,
+};
+use rustc_data_structures::intern::Interned;
+use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
+use rustc_middle::ty::{self, RePlaceholder, Region};
+
+impl<'tcx> NiceRegionError<'_, 'tcx> {
+ /// Emitted wwhen given a `ConcreteFailure` when relating two placeholders.
+ pub(super) fn try_report_placeholder_relation(
+ &self,
+ ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
+ match &self.error {
+ Some(RegionResolutionError::ConcreteFailure(
+ SubregionOrigin::RelateRegionParamBound(span),
+ Region(Interned(RePlaceholder(ty::Placeholder { name: sub_name, .. }), _)),
+ Region(Interned(RePlaceholder(ty::Placeholder { name: sup_name, .. }), _)),
+ )) => {
+ let msg = "lifetime bound not satisfied";
+ let mut err = self.tcx().sess.struct_span_err(*span, msg);
+ let (sub_span, sub_symbol) = match sub_name {
+ ty::BrNamed(def_id, symbol) => {
+ (Some(self.tcx().def_span(def_id)), Some(symbol))
+ }
+ ty::BrAnon(_, span) => (*span, None),
+ ty::BrEnv => (None, None),
+ };
+ let (sup_span, sup_symbol) = match sup_name {
+ ty::BrNamed(def_id, symbol) => {
+ (Some(self.tcx().def_span(def_id)), Some(symbol))
+ }
+ ty::BrAnon(_, span) => (*span, None),
+ ty::BrEnv => (None, None),
+ };
+ match (sub_span, sup_span, sub_symbol, sup_symbol) {
+ (Some(sub_span), Some(sup_span), Some(sub_symbol), Some(sup_symbol)) => {
+ err.span_note(
+ sub_span,
+ format!("the lifetime `{sub_symbol}` defined here..."),
+ );
+ err.span_note(
+ sup_span,
+ format!("...must outlive the lifetime `{sup_symbol}` defined here"),
+ );
+ }
+ (Some(sub_span), Some(sup_span), _, Some(sup_symbol)) => {
+ err.span_note(sub_span, format!("the lifetime defined here..."));
+ err.span_note(
+ sup_span,
+ format!("...must outlive the lifetime `{sup_symbol}` defined here"),
+ );
+ }
+ (Some(sub_span), Some(sup_span), Some(sub_symbol), _) => {
+ err.span_note(
+ sub_span,
+ format!("the lifetime `{sub_symbol}` defined here..."),
+ );
+ err.span_note(
+ sup_span,
+ format!("...must outlive the lifetime defined here"),
+ );
+ }
+ (Some(sub_span), Some(sup_span), _, _) => {
+ err.span_note(sub_span, format!("the lifetime defined here..."));
+ err.span_note(
+ sup_span,
+ format!("...must outlive the lifetime defined here"),
+ );
+ }
+ _ => {}
+ }
+ err.note("this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)");
+ Some(err)
+ }
+
+ _ => None,
+ }
+ }
+}
use crate::infer::lexical_region_resolve::RegionResolutionError;
use crate::infer::{SubregionOrigin, TypeTrace};
use crate::traits::{ObligationCauseCode, UnifyReceiverContext};
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{walk_ty, Visitor};
// Same case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a `'static`
// lifetime as above, but called using a fully-qualified path to the method:
// `Foo::qux(bar)`.
- let mut v = TraitObjectVisitor(FxHashSet::default());
+ let mut v = TraitObjectVisitor(FxIndexSet::default());
v.visit_ty(param.param_ty);
if let Some((ident, self_ty)) =
self.get_impl_ident_and_self_ty_from_trait(item_def_id, &v.0)
};
// Get the identity type for this RPIT
- let did = item_id.def_id.to_def_id();
+ let did = item_id.owner_id.to_def_id();
let ty = tcx.mk_opaque(did, ty::InternalSubsts::identity_for_item(tcx, did));
if let Some(span) = opaque
fn get_impl_ident_and_self_ty_from_trait(
&self,
def_id: DefId,
- trait_objects: &FxHashSet<DefId>,
+ trait_objects: &FxIndexSet<DefId>,
) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
let tcx = self.tcx();
match tcx.hir().get_if_local(def_id) {
return false;
};
- let mut v = TraitObjectVisitor(FxHashSet::default());
+ let mut v = TraitObjectVisitor(FxIndexSet::default());
v.visit_ty(ty);
// Get the `Ident` of the method being called and the corresponding `impl` (to point at
fn suggest_constrain_dyn_trait_in_impl(
&self,
err: &mut Diagnostic,
- found_dids: &FxHashSet<DefId>,
+ found_dids: &FxIndexSet<DefId>,
ident: Ident,
self_ty: &hir::Ty<'_>,
) -> bool {
}
/// Collect all the trait objects in a type that could have received an implicit `'static` lifetime.
-pub struct TraitObjectVisitor(pub FxHashSet<DefId>);
+pub struct TraitObjectVisitor(pub FxIndexSet<DefId>);
impl<'tcx> TypeVisitor<'tcx> for TraitObjectVisitor {
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
region: ty::BoundRegionKind,
) -> bool {
let late_bound_regions = self.tcx().collect_referenced_late_bound_regions(&ty);
+ // We are only checking is any region meets the condition so order doesn't matter
+ #[allow(rustc::potential_query_instability)]
late_bound_regions.iter().any(|r| *r == region)
}
}))
},
consts: &mut |bound_var: ty::BoundVar, ty| {
- self.tcx.mk_const(ty::ConstS {
- kind: ty::ConstKind::Placeholder(ty::PlaceholderConst {
+ self.tcx.mk_const(
+ ty::ConstKind::Placeholder(ty::PlaceholderConst {
universe: next_universe,
name: bound_var,
}),
ty,
- })
+ )
},
};
// are placeholders as upper bounds, but the universe of the
// variable `'a`, or some variable that `'a` has to outlive, doesn't
// permit those placeholders.
+ //
+ // We only iterate to find the min, which means it doesn't cause reproducibility issues
+ #[allow(rustc::potential_query_instability)]
let min_universe = lower_vid_bounds
.into_iter()
.map(|vid| self.var_infos[vid].universe)
static_assert_size!(SubregionOrigin<'_>, 32);
impl<'tcx> SubregionOrigin<'tcx> {
- pub fn to_constraint_category(&self) -> ConstraintCategory {
+ pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> {
match self {
Self::Subtype(type_trace) => type_trace.cause.to_constraint_category(),
Self::AscribeUserTypeProvePredicate(span) => ConstraintCategory::Predicate(*span),
impl<'tcx> InferCtxt<'tcx> {
/// Creates a `TypeErrCtxt` for emitting various inference errors.
- /// During typeck, use `FnCtxt::infer_err` instead.
+ /// During typeck, use `FnCtxt::err_ctxt` instead.
pub fn err_ctxt(&self) -> TypeErrCtxt<'_, 'tcx> {
- TypeErrCtxt { infcx: self, typeck_results: None }
+ TypeErrCtxt { infcx: self, typeck_results: None, fallback_has_occurred: false }
}
/// calls `tcx.try_unify_abstract_consts` after
if ty.has_non_region_param() || ty.has_non_region_infer() {
bug!("const `{ct}`'s type should not reference params or types");
}
- tcx.mk_const(ty::ConstS {
- ty,
- kind: ty::ConstKind::Placeholder(ty::PlaceholderConst {
+ tcx.mk_const(
+ ty::ConstKind::Placeholder(ty::PlaceholderConst {
universe: ty::UniverseIndex::ROOT,
name: ty::BoundVar::from_usize(idx),
}),
- })
+ ty,
+ )
.into()
}
_ => arg,
use crate::infer::InferCtxt;
use crate::infer::{ConstVarValue, ConstVariableValue};
use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
+use crate::traits::PredicateObligation;
use rustc_data_structures::fx::FxHashMap;
+use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
);
fn const_equate(&mut self, a: ty::Const<'tcx>, b: ty::Const<'tcx>);
- fn register_opaque_type(
+ fn register_opaque_type_obligations(
&mut self,
- a: Ty<'tcx>,
- b: Ty<'tcx>,
- a_is_expected: bool,
+ obligations: Vec<PredicateObligation<'tcx>>,
) -> Result<(), TypeError<'tcx>>;
/// Creates a new universe index. Used when instantiating placeholders.
(_, &ty::Opaque(..)) => (generalize(a, true)?, b),
_ => unreachable!(),
};
- self.delegate.register_opaque_type(a, b, true)?;
+ let cause = ObligationCause::dummy_with_span(self.delegate.span());
+ let obligations = self
+ .infcx
+ .handle_opaque_type(a, b, true, &cause, self.delegate.param_env())?
+ .obligations;
+ self.delegate.register_opaque_type_obligations(obligations)?;
trace!(a = ?a.kind(), b = ?b.kind(), "opaque type instantiated");
Ok(a)
}
(&ty::Infer(ty::TyVar(vid)), _) => self.relate_ty_var((vid, b)),
(&ty::Opaque(a_def_id, _), &ty::Opaque(b_def_id, _)) if a_def_id == b_def_id => {
- infcx.commit_if_ok(|_| infcx.super_combine_tys(self, a, b)).or_else(|err| {
+ infcx.super_combine_tys(self, a, b).or_else(|err| {
self.tcx().sess.delay_span_bug(
self.delegate.span(),
"failure to relate an opaque to itself should result in an error later on",
return Ok(InferOk { value: (), obligations: vec![] });
}
let (a, b) = if a_is_expected { (a, b) } else { (b, a) };
- let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() {
+ let process = |a: Ty<'tcx>, b: Ty<'tcx>, a_is_expected| match *a.kind() {
ty::Opaque(def_id, substs) if def_id.is_local() => {
let def_id = def_id.expect_local();
let origin = match self.defining_use_anchor {
param_env,
b,
origin,
+ a_is_expected,
))
}
_ => None,
};
- if let Some(res) = process(a, b) {
+ if let Some(res) = process(a, b, true) {
res
- } else if let Some(res) = process(b, a) {
+ } else if let Some(res) = process(b, a, false) {
res
} else {
let (a, b) = self.resolve_vars_if_possible((a, b));
impl<'tcx> InferCtxt<'tcx> {
#[instrument(skip(self), level = "debug")]
- pub fn register_hidden_type(
+ fn register_hidden_type(
&self,
opaque_type_key: OpaqueTypeKey<'tcx>,
cause: ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
hidden_ty: Ty<'tcx>,
origin: hir::OpaqueTyOrigin,
+ a_is_expected: bool,
) -> InferResult<'tcx, ()> {
let tcx = self.tcx;
let OpaqueTypeKey { def_id, substs } = opaque_type_key;
origin,
);
if let Some(prev) = prev {
- obligations = self.at(&cause, param_env).eq(prev, hidden_ty)?.obligations;
+ obligations =
+ self.at(&cause, param_env).eq_exp(a_is_expected, prev, hidden_ty)?.obligations;
}
let item_bounds = tcx.bound_explicit_item_bounds(def_id.to_def_id());
origin: SubregionOrigin<'tcx>,
a: ty::Region<'tcx>,
b: ty::Region<'tcx>,
- constraint_category: ConstraintCategory,
+ constraint_category: ConstraintCategory<'tcx>,
);
fn push_verify(
origin: infer::SubregionOrigin<'tcx>,
ty: Ty<'tcx>,
region: ty::Region<'tcx>,
- category: ConstraintCategory,
+ category: ConstraintCategory<'tcx>,
) {
assert!(!ty.has_escaping_bound_vars());
origin: infer::SubregionOrigin<'tcx>,
components: &[Component<'tcx>],
region: ty::Region<'tcx>,
- category: ConstraintCategory,
+ category: ConstraintCategory<'tcx>,
) {
for component in components.iter() {
let origin = origin.clone();
origin: SubregionOrigin<'tcx>,
a: ty::Region<'tcx>,
b: ty::Region<'tcx>,
- _constraint_category: ConstraintCategory,
+ _constraint_category: ConstraintCategory<'tcx>,
) {
self.sub_regions(origin, a, b)
}
use super::*;
use crate::infer::CombinedSnapshot;
use rustc_data_structures::{
+ fx::FxIndexMap,
graph::{scc::Sccs, vec_graph::VecGraph},
undo_log::UndoLogs,
};
/// an edge `R1 -> R2` in the graph.
struct MiniGraph<'tcx> {
/// Map from a region to the index of the node in the graph.
- nodes: FxHashMap<ty::Region<'tcx>, LeakCheckNode>,
+ nodes: FxIndexMap<ty::Region<'tcx>, LeakCheckNode>,
/// Map from node index to SCC, and stores the successors of each SCC. All
/// the regions in the same SCC are equal to one another, and if `S1 -> S2`,
where
'tcx: 'a,
{
- let mut nodes = FxHashMap::default();
+ let mut nodes = FxIndexMap::default();
let mut edges = Vec::new();
// Note that if `R2: R1`, we get a callback `r1, r2`, so `target` is first parameter.
}
fn add_node(
- nodes: &mut FxHashMap<ty::Region<'tcx>, LeakCheckNode>,
+ nodes: &mut FxIndexMap<ty::Region<'tcx>, LeakCheckNode>,
r: ty::Region<'tcx>,
) -> LeakCheckNode {
let l = nodes.len();
InferCtxtUndoLogs, MiscVariable, RegionVariableOrigin, Rollback, Snapshot, SubregionOrigin,
};
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_data_structures::intern::Interned;
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::undo_log::UndoLogs;
/// we record the fact that `'a <= 'b` is implied by the fn
/// signature, and then ignore the constraint when solving
/// equations. This is a bit of a hack but seems to work.
- pub givens: FxHashSet<(Region<'tcx>, ty::RegionVid)>,
+ pub givens: FxIndexSet<(Region<'tcx>, ty::RegionVid)>,
}
/// Represents a constraint that influences the inference process.
use super::SubregionOrigin;
use crate::infer::combine::ConstEquateRelation;
-use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::traits::Obligation;
-use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::relate::{Cause, Relate, RelateResult, TypeRelation};
use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::TyVar;
(&ty::Opaque(did, ..), _) | (_, &ty::Opaque(did, ..))
if self.fields.define_opaque_types && did.is_local() =>
{
- let mut generalize = |ty, ty_is_expected| {
- let var = infcx.next_ty_var_id_in_universe(
- TypeVariableOrigin {
- kind: TypeVariableOriginKind::MiscVariable,
- span: self.fields.trace.cause.span,
- },
- ty::UniverseIndex::ROOT,
- );
- self.fields.instantiate(ty, RelationDir::SubtypeOf, var, ty_is_expected)?;
- Ok(infcx.tcx.mk_ty_var(var))
- };
- let (a, b) = if self.a_is_expected { (a, b) } else { (b, a) };
- let (ga, gb) = match (a.kind(), b.kind()) {
- (&ty::Opaque(..), _) => (a, generalize(b, true)?),
- (_, &ty::Opaque(..)) => (generalize(a, false)?, b),
- _ => unreachable!(),
- };
self.fields.obligations.extend(
infcx
- .handle_opaque_type(ga, gb, true, &self.fields.trace.cause, self.param_env())
- // Don't leak any generalized type variables out of this
- // subtyping relation in the case of a type error.
- .map_err(|err| {
- let (ga, gb) = self.fields.infcx.resolve_vars_if_possible((ga, gb));
- if let TypeError::Sorts(sorts) = err && sorts.expected == ga && sorts.found == gb {
- TypeError::Sorts(ExpectedFound { expected: a, found: b })
- } else {
- err
- }
- })?
+ .handle_opaque_type(
+ a,
+ b,
+ self.a_is_expected,
+ &self.fields.trace.cause,
+ self.param_env(),
+ )?
.obligations,
);
- Ok(ga)
+ Ok(a)
}
// Optimization of GeneratorWitness relation since we know that all
// free regions are replaced with bound regions during construction.
//!
//! This API is completely unstable and subject to change.
-#![allow(rustc::potential_query_instability)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(box_patterns)]
#![feature(control_flow_enum)]
use super::ObjectSafetyViolation;
use crate::infer::InferCtxt;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{struct_span_err, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
);
err.span_label(span, format!("`{}` cannot be made into an object", trait_str));
- let mut reported_violations = FxHashSet::default();
+ let mut reported_violations = FxIndexSet::default();
let mut multi_span = vec![];
let mut messages = vec![];
for violation in violations {
rustc_trait_selection = { path = "../rustc_trait_selection" }
rustc_ty_utils = { path = "../rustc_ty_utils" }
-[target.'cfg(unix)'.dependencies]
-libc = "0.2"
-
-[target.'cfg(windows)'.dependencies]
-winapi = { version = "0.3", features = ["libloaderapi"] }
-
[dev-dependencies]
rustc_target = { path = "../rustc_target" }
sess.time("misc_checking_3", || {
parallel!(
{
- tcx.ensure().privacy_access_levels(());
+ tcx.ensure().effective_visibilities(());
parallel!(
{
use rustc_span::symbol::sym;
fn proc_macro_decls_static(tcx: TyCtxt<'_>, (): ()) -> Option<LocalDefId> {
- let mut finder = Finder { tcx, decls: None };
+ let mut decls = None;
for id in tcx.hir().items() {
- let attrs = finder.tcx.hir().attrs(id.hir_id());
- if finder.tcx.sess.contains_name(attrs, sym::rustc_proc_macro_decls) {
- finder.decls = Some(id.def_id.def_id);
+ let attrs = tcx.hir().attrs(id.hir_id());
+ if tcx.sess.contains_name(attrs, sym::rustc_proc_macro_decls) {
+ decls = Some(id.owner_id.def_id);
}
}
- finder.decls
-}
-
-struct Finder<'tcx> {
- tcx: TyCtxt<'tcx>,
- decls: Option<LocalDefId>,
+ decls
}
pub(crate) fn provide(providers: &mut Providers) {
untracked!(time_llvm_passes, true);
untracked!(time_passes, true);
untracked!(trace_macros, true);
+ untracked!(track_diagnostics, true);
untracked!(trim_diagnostic_paths, false);
untracked!(ui_testing, true);
untracked!(unpretty, Some("expanded".to_string()));
use rustc_session::config::CheckCfg;
use rustc_session::config::{self, CrateType};
use rustc_session::config::{ErrorOutputType, Input, OutputFilenames};
+use rustc_session::filesearch::sysroot_candidates;
use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer};
use rustc_session::parse::CrateConfig;
use rustc_session::{early_error, filesearch, output, Session};
let bundle = match rustc_errors::fluent_bundle(
sopts.maybe_sysroot.clone(),
- sysroot_candidates(),
+ sysroot_candidates().to_vec(),
sopts.unstable_opts.translate_lang.clone(),
sopts.unstable_opts.translate_additional_ftl.as_deref(),
sopts.unstable_opts.translate_directionality_markers,
})
}
-fn sysroot_candidates() -> Vec<PathBuf> {
- let target = session::config::host_triple();
- let mut sysroot_candidates = vec![filesearch::get_or_default_sysroot()];
- let path = current_dll_path().and_then(|s| s.canonicalize().ok());
- if let Some(dll) = path {
- // use `parent` twice to chop off the file name and then also the
- // directory containing the dll which should be either `lib` or `bin`.
- if let Some(path) = dll.parent().and_then(|p| p.parent()) {
- // The original `path` pointed at the `rustc_driver` crate's dll.
- // Now that dll should only be in one of two locations. The first is
- // in the compiler's libdir, for example `$sysroot/lib/*.dll`. The
- // other is the target's libdir, for example
- // `$sysroot/lib/rustlib/$target/lib/*.dll`.
- //
- // We don't know which, so let's assume that if our `path` above
- // ends in `$target` we *could* be in the target libdir, and always
- // assume that we may be in the main libdir.
- sysroot_candidates.push(path.to_owned());
-
- if path.ends_with(target) {
- sysroot_candidates.extend(
- path.parent() // chop off `$target`
- .and_then(|p| p.parent()) // chop off `rustlib`
- .and_then(|p| p.parent()) // chop off `lib`
- .map(|s| s.to_owned()),
- );
- }
- }
- }
-
- return sysroot_candidates;
-
- #[cfg(unix)]
- fn current_dll_path() -> Option<PathBuf> {
- use std::ffi::{CStr, OsStr};
- use std::os::unix::prelude::*;
-
- unsafe {
- let addr = current_dll_path as usize as *mut _;
- let mut info = mem::zeroed();
- if libc::dladdr(addr, &mut info) == 0 {
- info!("dladdr failed");
- return None;
- }
- if info.dli_fname.is_null() {
- info!("dladdr returned null pointer");
- return None;
- }
- let bytes = CStr::from_ptr(info.dli_fname).to_bytes();
- let os = OsStr::from_bytes(bytes);
- Some(PathBuf::from(os))
- }
- }
-
- #[cfg(windows)]
- fn current_dll_path() -> Option<PathBuf> {
- use std::ffi::OsString;
- use std::io;
- use std::os::windows::prelude::*;
- use std::ptr;
-
- use winapi::um::libloaderapi::{
- GetModuleFileNameW, GetModuleHandleExW, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
- };
-
- unsafe {
- let mut module = ptr::null_mut();
- let r = GetModuleHandleExW(
- GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
- current_dll_path as usize as *mut _,
- &mut module,
- );
- if r == 0 {
- info!("GetModuleHandleExW failed: {}", io::Error::last_os_error());
- return None;
- }
- let mut space = Vec::with_capacity(1024);
- let r = GetModuleFileNameW(module, space.as_mut_ptr(), space.capacity() as u32);
- if r == 0 {
- info!("GetModuleFileNameW failed: {}", io::Error::last_os_error());
- return None;
- }
- let r = r as usize;
- if r >= space.capacity() {
- info!("our buffer was too small? {}", io::Error::last_os_error());
- return None;
- }
- space.set_len(r);
- let os = OsString::from_wide(&space);
- Some(PathBuf::from(os))
- }
- }
-}
-
fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> MakeBackendFn {
// For now we only allow this function to be called once as it'll dlopen a
// few things, which seems to work best if we only do that once. In
/// tokens.
UnknownPrefix,
- /// Examples: `"12_u8"`, `"1.0e-40"`, `b"123`.
+ /// Examples: `12u8`, `1.0e-40`, `b"123"`. Note that `_` is an invalid
+ /// suffix, but may be present here on string and float literals. Users of
+ /// this type will need to check for and reject that case.
///
/// See [LiteralKind] for more details.
Literal { kind: LiteralKind, suffix_start: u32 },
self.eat_decimal_digits()
}
- // Eats the suffix of the literal, e.g. "_u8".
+ // Eats the suffix of the literal, e.g. "u8".
fn eat_literal_suffix(&mut self) {
self.eat_identifier();
}
- // Eats the identifier.
+ // Eats the identifier. Note: succeeds on `_`, which isn't a valid
+ // identifer.
fn eat_identifier(&mut self) {
if !is_id_start(self.first()) {
return;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdSet, CRATE_DEF_ID};
-use rustc_hir::{ForeignItemKind, GenericParamKind, HirId, PatKind, PredicateOrigin};
+use rustc_hir::{ForeignItemKind, GenericParamKind, HirId, Node, PatKind, PredicateOrigin};
use rustc_index::vec::Idx;
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::layout::{LayoutError, LayoutOf};
| hir::ItemKind::Enum(..)
| hir::ItemKind::Struct(..)
| hir::ItemKind::Union(..) => {
- self.check_heap_type(cx, it.span, cx.tcx.type_of(it.def_id))
+ self.check_heap_type(cx, it.span, cx.tcx.type_of(it.owner_id))
}
_ => (),
}
// It's an option so the crate root can also use this function (it doesn't
// have a `NodeId`).
if def_id != CRATE_DEF_ID {
- if !cx.access_levels.is_exported(def_id) {
+ if !cx.effective_visibilities.is_exported(def_id) {
return;
}
}
match it.kind {
hir::ItemKind::Trait(..) => {
// Issue #11592: traits are always considered exported, even when private.
- if cx.tcx.visibility(it.def_id)
+ if cx.tcx.visibility(it.owner_id)
== ty::Visibility::Restricted(
- cx.tcx.parent_module_from_def_id(it.def_id.def_id).to_def_id(),
+ cx.tcx.parent_module_from_def_id(it.owner_id.def_id).to_def_id(),
)
{
return;
_ => return,
};
- let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id());
+ let (article, desc) = cx.tcx.article_and_description(it.owner_id.to_def_id());
- self.check_missing_docs_attrs(cx, it.def_id.def_id, article, desc);
+ self.check_missing_docs_attrs(cx, it.owner_id.def_id, article, desc);
}
fn check_trait_item(&mut self, cx: &LateContext<'_>, trait_item: &hir::TraitItem<'_>) {
- let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id());
+ let (article, desc) = cx.tcx.article_and_description(trait_item.owner_id.to_def_id());
- self.check_missing_docs_attrs(cx, trait_item.def_id.def_id, article, desc);
+ self.check_missing_docs_attrs(cx, trait_item.owner_id.def_id, article, desc);
}
fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
}
}
- let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
- self.check_missing_docs_attrs(cx, impl_item.def_id.def_id, article, desc);
+ let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id());
+ self.check_missing_docs_attrs(cx, impl_item.owner_id.def_id, article, desc);
}
fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'_>) {
- let (article, desc) = cx.tcx.article_and_description(foreign_item.def_id.to_def_id());
- self.check_missing_docs_attrs(cx, foreign_item.def_id.def_id, article, desc);
+ let (article, desc) = cx.tcx.article_and_description(foreign_item.owner_id.to_def_id());
+ self.check_missing_docs_attrs(cx, foreign_item.owner_id.def_id, article, desc);
}
fn check_field_def(&mut self, cx: &LateContext<'_>, sf: &hir::FieldDef<'_>) {
impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
- if !cx.access_levels.is_reachable(item.def_id.def_id) {
+ if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) {
return;
}
let (def, ty) = match item.kind {
if !ast_generics.params.is_empty() {
return;
}
- let def = cx.tcx.adt_def(item.def_id);
+ let def = cx.tcx.adt_def(item.owner_id);
(def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
}
hir::ItemKind::Union(_, ref ast_generics) => {
if !ast_generics.params.is_empty() {
return;
}
- let def = cx.tcx.adt_def(item.def_id);
+ let def = cx.tcx.adt_def(item.owner_id);
(def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
}
hir::ItemKind::Enum(_, ref ast_generics) => {
if !ast_generics.params.is_empty() {
return;
}
- let def = cx.tcx.adt_def(item.def_id);
+ let def = cx.tcx.adt_def(item.owner_id);
(def, cx.tcx.mk_adt(def, cx.tcx.intern_substs(&[])))
}
_ => return,
return;
}
let param_env = ty::ParamEnv::empty();
- if ty.is_copy_modulo_regions(cx.tcx.at(item.span), param_env) {
+ if ty.is_copy_modulo_regions(cx.tcx, param_env) {
return;
}
if can_type_implement_copy(
impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
- if !cx.access_levels.is_reachable(item.def_id.def_id) {
+ if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) {
return;
}
debug!("{:?}", self.impling_types);
}
- if !self.impling_types.as_ref().unwrap().contains(&item.def_id.def_id) {
+ if !self.impling_types.as_ref().unwrap().contains(&item.owner_id.def_id) {
cx.struct_span_lint(
MISSING_DEBUG_IMPLEMENTATIONS,
item.span,
check_no_mangle_on_generic_fn(
no_mangle_attr,
Some(generics),
- cx.tcx.hir().get_generics(it.id.def_id.def_id).unwrap(),
+ cx.tcx.hir().get_generics(it.id.owner_id.def_id).unwrap(),
it.span,
);
}
exportable: bool,
) {
let mut applicability = Applicability::MachineApplicable;
- if cx.tcx.visibility(def_id).is_public() && !cx.access_levels.is_reachable(def_id) {
+ if cx.tcx.visibility(def_id).is_public() && !cx.effective_visibilities.is_reachable(def_id)
+ {
if vis_span.from_expansion() {
applicability = Applicability::MaybeIncorrect;
}
if let hir::ItemKind::Use(_, hir::UseKind::ListStem) = &item.kind {
return;
}
- self.perform_lint(cx, "item", item.def_id.def_id, item.vis_span, true);
+ self.perform_lint(cx, "item", item.owner_id.def_id, item.vis_span, true);
}
fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'tcx>) {
- self.perform_lint(cx, "item", foreign_item.def_id.def_id, foreign_item.vis_span, true);
+ self.perform_lint(cx, "item", foreign_item.owner_id.def_id, foreign_item.vis_span, true);
}
fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
- let def_id = cx.tcx.hir().local_def_id(field.hir_id);
+ let map = cx.tcx.hir();
+ let def_id = map.local_def_id(field.hir_id);
+ if matches!(map.get(map.get_parent_node(field.hir_id)), Node::Variant(_)) {
+ return;
+ }
self.perform_lint(cx, "field", def_id, field.vis_span, false);
}
fn check_impl_item(&mut self, cx: &LateContext<'_>, impl_item: &hir::ImplItem<'_>) {
// Only lint inherent impl items.
- if cx.tcx.associated_item(impl_item.def_id).trait_item_def_id.is_none() {
- self.perform_lint(cx, "item", impl_item.def_id.def_id, impl_item.vis_span, false);
+ if cx.tcx.associated_item(impl_item.owner_id).trait_item_def_id.is_none() {
+ self.perform_lint(cx, "item", impl_item.owner_id.def_id, impl_item.vis_span, false);
}
}
}
use rustc_middle::ty::PredicateKind::*;
if cx.tcx.features().trivial_bounds {
- let predicates = cx.tcx.predicates_of(item.def_id);
+ let predicates = cx.tcx.predicates_of(item.owner_id);
for &(predicate, span) in predicates.predicates {
let predicate_kind_name = match predicate.kind().skip_binder() {
Trait(..) => "trait",
if let hir::ItemKind::Mod(..) = it.kind {
} else {
self.items_nameable = false;
- self.boundary = Some(it.def_id);
+ self.boundary = Some(it.owner_id);
}
return;
}
}
fn check_item_post(&mut self, _cx: &LateContext<'_>, it: &hir::Item<'_>) {
- if !self.items_nameable && self.boundary == Some(it.def_id) {
+ if !self.items_nameable && self.boundary == Some(it.owner_id) {
self.items_nameable = true;
}
}
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
use rustc_middle::middle::resolve_lifetime::Region;
- let def_id = item.def_id.def_id;
+ let def_id = item.owner_id.def_id;
if let hir::ItemKind::Struct(_, ref hir_generics)
| hir::ItemKind::Enum(_, ref hir_generics)
| hir::ItemKind::Union(_, ref hir_generics) = item.kind
/// Insert a new foreign item into the seen set. If a symbol with the same name already exists
/// for the item, return its HirId without updating the set.
fn insert(&mut self, tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> Option<HirId> {
- let did = fi.def_id.to_def_id();
+ let did = fi.owner_id.to_def_id();
let instance = Instance::new(did, ty::List::identity_for_item(tcx, did));
let name = Symbol::intern(tcx.symbol_name(instance).name);
if let Some(&hir_id) = self.seen_decls.get(&name) {
/// symbol's name.
fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> SymbolName {
if let Some((overridden_link_name, overridden_link_name_span)) =
- tcx.codegen_fn_attrs(fi.def_id).link_name.map(|overridden_link_name| {
+ tcx.codegen_fn_attrs(fi.owner_id).link_name.map(|overridden_link_name| {
// FIXME: Instead of searching through the attributes again to get span
// information, we could have codegen_fn_attrs also give span information back for
// where the attribute was defined. However, until this is found to be a
// bottleneck, this does just fine.
(
overridden_link_name,
- tcx.get_attr(fi.def_id.to_def_id(), sym::link_name).unwrap().span,
+ tcx.get_attr(fi.owner_id.to_def_id(), sym::link_name).unwrap().span,
)
})
{
let tcx = cx.tcx;
if let Some(existing_hid) = self.insert(tcx, this_fi) {
let existing_decl_ty = tcx.type_of(tcx.hir().local_def_id(existing_hid));
- let this_decl_ty = tcx.type_of(this_fi.def_id);
+ let this_decl_ty = tcx.type_of(this_fi.owner_id);
debug!(
"ClashingExternDeclarations: Comparing existing {:?}: {:?} to this {:?}: {:?}",
- existing_hid, existing_decl_ty, this_fi.def_id, this_decl_ty
+ existing_hid, existing_decl_ty, this_fi.owner_id, this_decl_ty
);
// Check that the declarations match.
if !Self::structurally_same_type(
use rustc_hir::def::Res;
use rustc_hir::def_id::{CrateNum, DefId};
use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
-use rustc_middle::middle::privacy::AccessLevels;
+use rustc_middle::middle::privacy::EffectiveVisibilities;
use rustc_middle::middle::stability;
use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
use rustc_middle::ty::print::with_no_trimmed_paths;
pub param_env: ty::ParamEnv<'tcx>,
/// Items accessible from the crate being checked.
- pub access_levels: &'tcx AccessLevels,
+ pub effective_visibilities: &'tcx EffectiveVisibilities,
/// The store of registered lints and the lint levels.
pub lint_store: &'tcx LintStore,
/// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
///
/// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
+ #[rustc_lint_diagnostics]
fn lookup_with_diagnostics(
&self,
lint: &'static Lint,
/// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
///
/// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
+ #[rustc_lint_diagnostics]
fn lookup<S: Into<MultiSpan>>(
&self,
lint: &'static Lint,
/// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
///
/// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
+ #[rustc_lint_diagnostics]
fn struct_span_lint<S: Into<MultiSpan>>(
&self,
lint: &'static Lint,
/// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
///
/// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
+ #[rustc_lint_diagnostics]
fn lint(
&self,
lint: &'static Lint,
pub struct BuiltinEllpisisInclusiveRangePatterns {
#[primary_span]
pub span: Span,
- #[suggestion_short(code = "{replace}", applicability = "machine-applicable")]
+ #[suggestion(style = "short", code = "{replace}", applicability = "machine-applicable")]
pub suggestion: Span,
pub replace: String,
}
use hir::{Expr, Pat};
use rustc_errors::{Applicability, DelayDm};
use rustc_hir as hir;
-use rustc_infer::traits::TraitEngine;
use rustc_infer::{infer::TyCtxtInferExt, traits::ObligationCause};
use rustc_middle::ty::{self, List};
use rustc_span::{sym, Span};
-use rustc_trait_selection::traits::TraitEngineExt;
declare_lint! {
/// The `for_loops_over_fallibles` lint checks for `for` loops over `Option` or `Result` values.
let ty = substs.type_at(0);
let infcx = cx.tcx.infer_ctxt().build();
- let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
-
let cause = ObligationCause::new(
span,
body_id.hir_id,
rustc_infer::traits::ObligationCauseCode::MiscObligation,
);
- fulfill_cx.register_bound(
+ let errors = rustc_trait_selection::traits::fully_solve_bound(
&infcx,
+ cause,
ty::ParamEnv::empty(),
// Erase any region vids from the type, which may not be resolved
infcx.tcx.erase_regions(ty),
into_iterator_did,
- cause,
);
- // Select all, including ambiguous predicates
- let errors = fulfill_cx.select_all_or_error(&infcx);
-
errors.is_empty()
}
module_def_id: LocalDefId,
pass: T,
) {
- let access_levels = &tcx.privacy_access_levels(());
+ let effective_visibilities = &tcx.effective_visibilities(());
let context = LateContext {
tcx,
enclosing_body: None,
cached_typeck_results: Cell::new(None),
param_env: ty::ParamEnv::empty(),
- access_levels,
+ effective_visibilities,
lint_store: unerased_lint_store(tcx),
last_node_with_lint_attrs: tcx.hir().local_def_id_to_hir_id(module_def_id),
generics: None,
}
fn late_lint_pass_crate<'tcx, T: LateLintPass<'tcx>>(tcx: TyCtxt<'tcx>, pass: T) {
- let access_levels = &tcx.privacy_access_levels(());
+ let effective_visibilities = &tcx.effective_visibilities(());
let context = LateContext {
tcx,
enclosing_body: None,
cached_typeck_results: Cell::new(None),
param_env: ty::ParamEnv::empty(),
- access_levels,
+ effective_visibilities,
lint_store: unerased_lint_store(tcx),
last_node_with_lint_attrs: hir::CRATE_HIR_ID,
generics: None,
/// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
///
/// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
+ #[rustc_lint_diagnostics]
pub(crate) fn struct_lint(
&self,
lint: &'static Lint,
#![feature(let_chains)]
#![feature(min_specialization)]
#![feature(never_type)]
+#![feature(rustc_attrs)]
#![recursion_limit = "256"]
#[macro_use]
TypeLimits: TypeLimits::new(),
NonSnakeCase: NonSnakeCase,
InvalidNoMangleItems: InvalidNoMangleItems,
- // Depends on access levels
+ // Depends on effective visibilities
UnreachablePub: UnreachablePub,
ExplicitOutlivesRequirements: ExplicitOutlivesRequirements,
InvalidValue: InvalidValue,
impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
let hir::ItemKind::OpaqueTy(_) = &item.kind else { return; };
- let def_id = item.def_id.def_id.to_def_id();
+ let def_id = item.owner_id.def_id.to_def_id();
let infcx = &cx.tcx.infer_ctxt().build();
// For every projection predicate in the opaque type's explicit bounds,
// check that the type that we're assigning actually satisfies the bounds
}
#[derive(Subdiagnostic)]
-#[suggestion_verbose(
+#[suggestion(
lint_opaque_hidden_inferred_bound_sugg,
+ style = "verbose",
applicability = "machine-applicable",
code = " + {trait_ref}"
)]
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
use rustc_middle::ty::PredicateKind::*;
- let predicates = cx.tcx.explicit_predicates_of(item.def_id);
+ let predicates = cx.tcx.explicit_predicates_of(item.owner_id);
for &(predicate, span) in predicates.predicates {
let Trait(trait_predicate) = predicate.kind().skip_binder() else {
continue
use rustc_middle::ty::{self, AdtKind, DefIdTree, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
use rustc_span::source_map;
use rustc_span::symbol::sym;
-use rustc_span::{Span, Symbol, DUMMY_SP};
+use rustc_span::{Span, Symbol};
use rustc_target::abi::{Abi, WrappingRange};
use rustc_target::abi::{Integer, TagEncoding, Variants};
use rustc_target::spec::abi::Abi as SpecAbi;
match *ty.kind() {
ty::Adt(def, substs) => {
if def.is_box() && matches!(self.mode, CItemKind::Definition) {
- if ty.boxed_ty().is_sized(tcx.at(DUMMY_SP), self.cx.param_env) {
+ if ty.boxed_ty().is_sized(tcx, self.cx.param_env) {
return FfiSafe;
} else {
return FfiUnsafe {
ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _)
if {
matches!(self.mode, CItemKind::Definition)
- && ty.is_sized(self.cx.tcx.at(DUMMY_SP), self.cx.param_env)
+ && ty.is_sized(self.cx.tcx, self.cx.param_env)
} =>
{
FfiSafe
impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences {
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
if let hir::ItemKind::Enum(ref enum_definition, _) = it.kind {
- let t = cx.tcx.type_of(it.def_id);
+ let t = cx.tcx.type_of(it.owner_id);
let ty = cx.tcx.erase_regions(t);
let Ok(layout) = cx.layout_of(ty) else { return };
let Variants::Multiple {
};
}
-declare_lint! {
- /// The `proc_macro_derive_resolution_fallback` lint detects proc macro
- /// derives using inaccessible names from parent modules.
- ///
- /// ### Example
- ///
- /// ```rust,ignore (proc-macro)
- /// // foo.rs
- /// #![crate_type = "proc-macro"]
- ///
- /// extern crate proc_macro;
- ///
- /// use proc_macro::*;
- ///
- /// #[proc_macro_derive(Foo)]
- /// pub fn foo1(a: TokenStream) -> TokenStream {
- /// drop(a);
- /// "mod __bar { static mut BAR: Option<Something> = None; }".parse().unwrap()
- /// }
- /// ```
- ///
- /// ```rust,ignore (needs-dependency)
- /// // bar.rs
- /// #[macro_use]
- /// extern crate foo;
- ///
- /// struct Something;
- ///
- /// #[derive(Foo)]
- /// struct Another;
- ///
- /// fn main() {}
- /// ```
- ///
- /// This will produce:
- ///
- /// ```text
- /// warning: cannot find type `Something` in this scope
- /// --> src/main.rs:8:10
- /// |
- /// 8 | #[derive(Foo)]
- /// | ^^^ names from parent modules are not accessible without an explicit import
- /// |
- /// = note: `#[warn(proc_macro_derive_resolution_fallback)]` on by default
- /// = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- /// = note: for more information, see issue #50504 <https://github.com/rust-lang/rust/issues/50504>
- /// ```
- ///
- /// ### Explanation
- ///
- /// If a proc-macro generates a module, the compiler unintentionally
- /// allowed items in that module to refer to items in the crate root
- /// without importing them. This is a [future-incompatible] lint to
- /// transition this to a hard error in the future. See [issue #50504] for
- /// more details.
- ///
- /// [issue #50504]: https://github.com/rust-lang/rust/issues/50504
- /// [future-incompatible]: ../index.md#future-incompatible-lints
- pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
- Deny,
- "detects proc macro derives using inaccessible names from parent modules",
- @future_incompatible = FutureIncompatibleInfo {
- reference: "issue #83583 <https://github.com/rust-lang/rust/issues/83583>",
- reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
- };
-}
-
declare_lint! {
/// The `macro_use_extern_crate` lint detects the use of the
/// [`macro_use` attribute].
UNSTABLE_NAME_COLLISIONS,
IRREFUTABLE_LET_PATTERNS,
WHERE_CLAUSES_OBJECT_SAFETY,
- PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
MACRO_USE_EXTERN_CRATE,
MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
ILL_FORMED_ATTRIBUTE_INPUT,
OptimizeNone = 24,
ReturnsTwice = 25,
ReadNone = 26,
- InaccessibleMemOnly = 27,
SanitizeHWAddress = 28,
WillReturn = 29,
StackProtectReq = 30,
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/IntrinsicsARM.h"
#include "llvm/IR/Mangler.h"
+#if LLVM_VERSION_GE(16, 0)
+#include "llvm/IR/ModRef.h"
+#endif
#include "llvm/Object/Archive.h"
#include "llvm/Object/COFFImportFile.h"
#include "llvm/Object/ObjectFile.h"
return Attribute::ReturnsTwice;
case ReadNone:
return Attribute::ReadNone;
- case InaccessibleMemOnly:
- return Attribute::InaccessibleMemOnly;
case SanitizeHWAddress:
return Attribute::SanitizeHWAddress;
case WillReturn:
#endif
}
+// Simplified representation of `MemoryEffects` across the FFI boundary.
+//
+// Each variant corresponds to one of the static factory methods on `MemoryEffects`.
+enum class LLVMRustMemoryEffects {
+ None,
+ ReadOnly,
+ InaccessibleMemOnly,
+};
+
+extern "C" LLVMAttributeRef LLVMRustCreateMemoryEffectsAttr(LLVMContextRef C,
+ LLVMRustMemoryEffects Effects) {
+#if LLVM_VERSION_GE(16, 0)
+ switch (Effects) {
+ case LLVMRustMemoryEffects::None:
+ return wrap(Attribute::getWithMemoryEffects(*unwrap(C), MemoryEffects::none()));
+ case LLVMRustMemoryEffects::ReadOnly:
+ return wrap(Attribute::getWithMemoryEffects(*unwrap(C), MemoryEffects::readOnly()));
+ case LLVMRustMemoryEffects::InaccessibleMemOnly:
+ return wrap(Attribute::getWithMemoryEffects(*unwrap(C),
+ MemoryEffects::inaccessibleMemOnly()));
+ default:
+ report_fatal_error("bad MemoryEffects.");
+ }
+#else
+ switch (Effects) {
+ case LLVMRustMemoryEffects::None:
+ return wrap(Attribute::get(*unwrap(C), Attribute::ReadNone));
+ case LLVMRustMemoryEffects::ReadOnly:
+ return wrap(Attribute::get(*unwrap(C), Attribute::ReadOnly));
+ case LLVMRustMemoryEffects::InaccessibleMemOnly:
+ return wrap(Attribute::get(*unwrap(C), Attribute::InaccessibleMemOnly));
+ default:
+ report_fatal_error("bad MemoryEffects.");
+ }
+#endif
+}
+
// Enable a fast-math flag
//
// https://llvm.org/docs/LangRef.html#fast-math-flags
for @Self
where G: rustc_errors::EmissionGuarantee
{
+
+ #[track_caller]
fn into_diagnostic(
self,
#handler: &'__diagnostic_handler_sess rustc_errors::Handler
let diag = &builder.diag;
structure.gen_impl(quote! {
gen impl<'__a> rustc_errors::DecorateLint<'__a, ()> for @Self {
+ #[track_caller]
fn decorate_lint<'__b>(
self,
#diag: &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()>
}
}
-/// Emit a error diagnostic for an invalid attribute (optionally performing additional decoration
+/// Emit an error diagnostic for an invalid attribute (optionally performing additional decoration
/// using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`.
///
/// For methods that return a `Result<_, DiagnosticDeriveError>`:
}
}
-/// Emit a error diagnostic for an invalid nested attribute (optionally performing additional
+/// Emit an error diagnostic for an invalid nested attribute (optionally performing additional
/// decoration using the `FnOnce` passed in `diag`) and return `Err(ErrorHandled)`.
///
/// For methods that return a `Result<_, DiagnosticDeriveError>`:
/// }
///
/// #[derive(Subdiagnostic)]
-/// #[suggestion_verbose(parser::raw_identifier)]
+/// #[suggestion(style = "verbose",parser::raw_identifier)]
/// pub struct RawIdentifierSuggestion<'tcx> {
/// #[primary_span]
/// span: Span,
use syn::{MetaList, MetaNameValue, NestedMeta, Path};
use synstructure::{BindingInfo, VariantInfo};
-use super::error::invalid_nested_attr;
+use super::error::{invalid_attr, invalid_nested_attr};
thread_local! {
pub static CODE_IDENT_COUNT: RefCell<u32> = RefCell::new(0);
}
/// Possible styles for suggestion subdiagnostics.
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, PartialEq)]
pub(super) enum SuggestionKind {
- /// `#[suggestion]`
Normal,
- /// `#[suggestion_short]`
Short,
- /// `#[suggestion_hidden]`
Hidden,
- /// `#[suggestion_verbose]`
Verbose,
+ ToolOnly,
}
impl FromStr for SuggestionKind {
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
- "" => Ok(SuggestionKind::Normal),
- "_short" => Ok(SuggestionKind::Short),
- "_hidden" => Ok(SuggestionKind::Hidden),
- "_verbose" => Ok(SuggestionKind::Verbose),
+ "normal" => Ok(SuggestionKind::Normal),
+ "short" => Ok(SuggestionKind::Short),
+ "hidden" => Ok(SuggestionKind::Hidden),
+ "verbose" => Ok(SuggestionKind::Verbose),
+ "tool-only" => Ok(SuggestionKind::ToolOnly),
_ => Err(()),
}
}
}
+impl fmt::Display for SuggestionKind {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ SuggestionKind::Normal => write!(f, "normal"),
+ SuggestionKind::Short => write!(f, "short"),
+ SuggestionKind::Hidden => write!(f, "hidden"),
+ SuggestionKind::Verbose => write!(f, "verbose"),
+ SuggestionKind::ToolOnly => write!(f, "tool-only"),
+ }
+ }
+}
+
impl SuggestionKind {
pub fn to_suggestion_style(&self) -> TokenStream {
match self {
SuggestionKind::Verbose => {
quote! { rustc_errors::SuggestionStyle::ShowAlways }
}
+ SuggestionKind::ToolOnly => {
+ quote! { rustc_errors::SuggestionStyle::CompletelyHidden }
+ }
+ }
+ }
+
+ fn from_suffix(s: &str) -> Option<Self> {
+ match s {
+ "" => Some(SuggestionKind::Normal),
+ "_short" => Some(SuggestionKind::Short),
+ "_hidden" => Some(SuggestionKind::Hidden),
+ "_verbose" => Some(SuggestionKind::Verbose),
+ _ => None,
}
}
}
let name = name.as_str();
let meta = attr.parse_meta()?;
+
let mut kind = match name {
"label" => SubdiagnosticKind::Label,
"note" => SubdiagnosticKind::Note,
"help" => SubdiagnosticKind::Help,
"warning" => SubdiagnosticKind::Warn,
_ => {
+ // Recover old `#[(multipart_)suggestion_*]` syntaxes
+ // FIXME(#100717): remove
if let Some(suggestion_kind) =
- name.strip_prefix("suggestion").and_then(|s| s.parse().ok())
+ name.strip_prefix("suggestion").and_then(SuggestionKind::from_suffix)
{
+ if suggestion_kind != SuggestionKind::Normal {
+ invalid_attr(attr, &meta)
+ .help(format!(
+ r#"Use `#[suggestion(..., style = "{}")]` instead"#,
+ suggestion_kind
+ ))
+ .emit();
+ }
+
SubdiagnosticKind::Suggestion {
- suggestion_kind,
+ suggestion_kind: SuggestionKind::Normal,
applicability: None,
code_field: new_code_ident(),
code_init: TokenStream::new(),
}
} else if let Some(suggestion_kind) =
- name.strip_prefix("multipart_suggestion").and_then(|s| s.parse().ok())
+ name.strip_prefix("multipart_suggestion").and_then(SuggestionKind::from_suffix)
{
- SubdiagnosticKind::MultipartSuggestion { suggestion_kind, applicability: None }
+ if suggestion_kind != SuggestionKind::Normal {
+ invalid_attr(attr, &meta)
+ .help(format!(
+ r#"Use `#[multipart_suggestion(..., style = "{}")]` instead"#,
+ suggestion_kind
+ ))
+ .emit();
+ }
+
+ SubdiagnosticKind::MultipartSuggestion {
+ suggestion_kind: SuggestionKind::Normal,
+ applicability: None,
+ }
} else {
throw_invalid_attr!(attr, &meta);
}
};
let mut code = None;
+ let mut suggestion_kind = None;
let mut nested_iter = nested.into_iter().peekable();
});
applicability.set_once(value, span);
}
+ (
+ "style",
+ SubdiagnosticKind::Suggestion { .. }
+ | SubdiagnosticKind::MultipartSuggestion { .. },
+ ) => {
+ let Some(value) = string_value else {
+ invalid_nested_attr(attr, &nested_attr).emit();
+ continue;
+ };
+
+ let value = value.value().parse().unwrap_or_else(|()| {
+ span_err(value.span().unwrap(), "invalid suggestion style")
+ .help("valid styles are `normal`, `short`, `hidden`, `verbose` and `tool-only`")
+ .emit();
+ SuggestionKind::Normal
+ });
+
+ suggestion_kind.set_once(value, span);
+ }
// Invalid nested attribute
(_, SubdiagnosticKind::Suggestion { .. }) => {
invalid_nested_attr(attr, &nested_attr)
- .help("only `code` and `applicability` are valid nested attributes")
+ .help(
+ "only `style`, `code` and `applicability` are valid nested attributes",
+ )
.emit();
}
(_, SubdiagnosticKind::MultipartSuggestion { .. }) => {
invalid_nested_attr(attr, &nested_attr)
- .help("only `applicability` is a valid nested attributes")
+ .help("only `style` and `applicability` are valid nested attributes")
.emit()
}
_ => {
}
match kind {
- SubdiagnosticKind::Suggestion { ref code_field, ref mut code_init, .. } => {
+ SubdiagnosticKind::Suggestion {
+ ref code_field,
+ ref mut code_init,
+ suggestion_kind: ref mut kind_field,
+ ..
+ } => {
+ if let Some(kind) = suggestion_kind.value() {
+ *kind_field = kind;
+ }
+
*code_init = if let Some(init) = code.value() {
init
} else {
quote! { let #code_field = std::iter::empty(); }
};
}
+ SubdiagnosticKind::MultipartSuggestion {
+ suggestion_kind: ref mut kind_field, ..
+ } => {
+ if let Some(kind) = suggestion_kind.value() {
+ *kind_field = kind;
+ }
+ }
SubdiagnosticKind::Label
| SubdiagnosticKind::Note
| SubdiagnosticKind::Help
- | SubdiagnosticKind::Warn
- | SubdiagnosticKind::MultipartSuggestion { .. } => {}
+ | SubdiagnosticKind::Warn => {}
}
Ok(Some((kind, slug)))
//! Validates all used crates and extern libraries and loads their metadata
use crate::errors::{
- ConflictingGlobalAlloc, CrateNotPanicRuntime, GlobalAllocRequired, NoMultipleGlobalAlloc,
- NoPanicStrategy, NoTransitiveNeedsDep, NotProfilerRuntime, ProfilerBuiltinsNeedsCore,
+ AllocFuncRequired, ConflictingAllocErrorHandler, ConflictingGlobalAlloc, CrateNotPanicRuntime,
+ GlobalAllocRequired, MissingAllocErrorHandler, NoMultipleAllocErrorHandler,
+ NoMultipleGlobalAlloc, NoPanicStrategy, NoTransitiveNeedsDep, NotProfilerRuntime,
+ ProfilerBuiltinsNeedsCore,
};
use crate::locator::{CrateError, CrateLocator, CratePaths};
use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
/// This crate needs an allocator and either provides it itself, or finds it in a dependency.
/// If the above is true, then this field denotes the kind of the found allocator.
allocator_kind: Option<AllocatorKind>,
+ /// This crate needs an allocation error handler and either provides it itself, or finds it in a dependency.
+ /// If the above is true, then this field denotes the kind of the found allocator.
+ alloc_error_handler_kind: Option<AllocatorKind>,
/// This crate has a `#[global_allocator]` item.
has_global_allocator: bool,
+ /// This crate has a `#[alloc_error_handler]` item.
+ has_alloc_error_handler: bool,
/// This map is used to verify we get no hash conflicts between
/// `StableCrateId` values.
self.allocator_kind
}
+ pub(crate) fn alloc_error_handler_kind(&self) -> Option<AllocatorKind> {
+ self.alloc_error_handler_kind
+ }
+
pub(crate) fn has_global_allocator(&self) -> bool {
self.has_global_allocator
}
+ pub(crate) fn has_alloc_error_handler(&self) -> bool {
+ self.has_alloc_error_handler
+ }
+
pub fn report_unused_deps(&self, tcx: TyCtxt<'_>) {
let json_unused_externs = tcx.sess.opts.json_unused_externs;
metas: IndexVec::from_elem_n(None, 1),
injected_panic_runtime: None,
allocator_kind: None,
+ alloc_error_handler_kind: None,
has_global_allocator: false,
+ has_alloc_error_handler: false,
stable_crate_ids,
unused_externs: Vec::new(),
},
}
spans => !spans.is_empty(),
};
+ self.cstore.has_alloc_error_handler = match &*alloc_error_handler_spans(&self.sess, krate) {
+ [span1, span2, ..] => {
+ self.sess.emit_err(NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 });
+ true
+ }
+ spans => !spans.is_empty(),
+ };
// Check to see if we actually need an allocator. This desire comes
// about through the `#![needs_allocator]` attribute and is typically
}
}
}
+ let mut alloc_error_handler =
+ self.cstore.has_alloc_error_handler.then(|| Symbol::intern("this crate"));
+ for (_, data) in self.cstore.iter_crate_data() {
+ if data.has_alloc_error_handler() {
+ match alloc_error_handler {
+ Some(other_crate) => {
+ self.sess.emit_err(ConflictingAllocErrorHandler {
+ crate_name: data.name(),
+ other_crate_name: other_crate,
+ });
+ }
+ None => alloc_error_handler = Some(data.name()),
+ }
+ }
+ }
if global_allocator.is_some() {
self.cstore.allocator_kind = Some(AllocatorKind::Global);
- return;
+ } else {
+ // Ok we haven't found a global allocator but we still need an
+ // allocator. At this point our allocator request is typically fulfilled
+ // by the standard library, denoted by the `#![default_lib_allocator]`
+ // attribute.
+ if !self.sess.contains_name(&krate.attrs, sym::default_lib_allocator)
+ && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator())
+ {
+ self.sess.emit_err(GlobalAllocRequired);
+ }
+ self.cstore.allocator_kind = Some(AllocatorKind::Default);
}
- // Ok we haven't found a global allocator but we still need an
- // allocator. At this point our allocator request is typically fulfilled
- // by the standard library, denoted by the `#![default_lib_allocator]`
- // attribute.
- if !self.sess.contains_name(&krate.attrs, sym::default_lib_allocator)
- && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator())
- {
- self.sess.emit_err(GlobalAllocRequired);
+ if alloc_error_handler.is_some() {
+ self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Global);
+ } else {
+ // The alloc crate provides a default allocation error handler if
+ // one isn't specified.
+ if !self.sess.features_untracked().default_alloc_error_handler {
+ self.sess.emit_err(AllocFuncRequired);
+ self.sess.emit_note(MissingAllocErrorHandler);
+ }
+ self.cstore.alloc_error_handler_kind = Some(AllocatorKind::Default);
}
- self.cstore.allocator_kind = Some(AllocatorKind::Default);
}
fn inject_dependency_if(
visit::walk_crate(&mut f, krate);
f.spans
}
+
+fn alloc_error_handler_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> {
+ struct Finder<'a> {
+ sess: &'a Session,
+ name: Symbol,
+ spans: Vec<Span>,
+ }
+ impl<'ast, 'a> visit::Visitor<'ast> for Finder<'a> {
+ fn visit_item(&mut self, item: &'ast ast::Item) {
+ if item.ident.name == self.name
+ && self.sess.contains_name(&item.attrs, sym::rustc_std_internal_symbol)
+ {
+ self.spans.push(item.span);
+ }
+ visit::walk_item(self, item)
+ }
+ }
+
+ let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::oom));
+ let mut f = Finder { sess, name, spans: Vec::new() };
+ visit::walk_crate(&mut f, krate);
+ f.spans
+}
pub span1: Span,
}
+#[derive(Diagnostic)]
+#[diag(metadata_no_multiple_alloc_error_handler)]
+pub struct NoMultipleAllocErrorHandler {
+ #[primary_span]
+ #[label]
+ pub span2: Span,
+ #[label(metadata_prev_alloc_error_handler)]
+ pub span1: Span,
+}
+
#[derive(Diagnostic)]
#[diag(metadata_conflicting_global_alloc)]
pub struct ConflictingGlobalAlloc {
pub other_crate_name: Symbol,
}
+#[derive(Diagnostic)]
+#[diag(metadata_conflicting_alloc_error_handler)]
+pub struct ConflictingAllocErrorHandler {
+ pub crate_name: Symbol,
+ pub other_crate_name: Symbol,
+}
+
#[derive(Diagnostic)]
#[diag(metadata_global_alloc_required)]
pub struct GlobalAllocRequired;
+#[derive(Diagnostic)]
+#[diag(metadata_alloc_func_required)]
+pub struct AllocFuncRequired;
+
+#[derive(Diagnostic)]
+#[diag(metadata_missing_alloc_error_handler)]
+pub struct MissingAllocErrorHandler;
+
#[derive(Diagnostic)]
#[diag(metadata_no_transitive_needs_dep)]
pub struct NoTransitiveNeedsDep<'a> {
}
impl IntoDiagnostic<'_> for InvalidMetadataFiles {
+ #[track_caller]
fn into_diagnostic(
self,
handler: &'_ rustc_errors::Handler,
}
impl IntoDiagnostic<'_> for CannotFindCrate {
+ #[track_caller]
fn into_diagnostic(
self,
handler: &'_ rustc_errors::Handler,
pub(crate) fn collect(tcx: TyCtxt<'_>) -> Vec<ForeignModule> {
let mut modules = Vec::new();
for id in tcx.hir().items() {
- if !matches!(tcx.def_kind(id.def_id), DefKind::ForeignMod) {
+ if !matches!(tcx.def_kind(id.owner_id), DefKind::ForeignMod) {
continue;
}
let item = tcx.hir().item(id);
if let hir::ItemKind::ForeignMod { items, .. } = item.kind {
- let foreign_items = items.iter().map(|it| it.id.def_id.to_def_id()).collect();
- modules.push(ForeignModule { foreign_items, def_id: id.def_id.to_def_id() });
+ let foreign_items = items.iter().map(|it| it.id.owner_id.to_def_id()).collect();
+ modules.push(ForeignModule { foreign_items, def_id: id.owner_id.to_def_id() });
}
}
modules
impl<'tcx> Collector<'tcx> {
fn process_item(&mut self, id: rustc_hir::ItemId) {
- if !matches!(self.tcx.def_kind(id.def_id), DefKind::ForeignMod) {
+ if !matches!(self.tcx.def_kind(id.owner_id), DefKind::ForeignMod) {
return;
}
}
_ => {
for child_item in foreign_mod_items {
- if self.tcx.def_kind(child_item.id.def_id).has_codegen_attrs()
+ if self.tcx.def_kind(child_item.id.owner_id).has_codegen_attrs()
&& self
.tcx
- .codegen_fn_attrs(child_item.id.def_id)
+ .codegen_fn_attrs(child_item.id.owner_id)
.link_ordinal
.is_some()
{
let link_ordinal_attr = self
.tcx
.hir()
- .attrs(child_item.id.def_id.into())
+ .attrs(child_item.id.owner_id.into())
.iter()
.find(|a| a.has_name(sym::link_ordinal))
.unwrap();
filename,
kind,
cfg,
- foreign_module: Some(it.def_id.to_def_id()),
+ foreign_module: Some(it.owner_id.to_def_id()),
wasm_import_module: wasm_import_module.map(|(name, _)| name),
verbatim,
dll_imports,
fn i686_arg_list_size(&self, item: &hir::ForeignItemRef) -> usize {
let argument_types: &List<Ty<'_>> = self.tcx.erase_late_bound_regions(
self.tcx
- .type_of(item.id.def_id)
+ .type_of(item.id.owner_id)
.fn_sig(self.tcx)
.inputs()
.map_bound(|slice| self.tcx.mk_type_list(slice.iter())),
}
};
- let codegen_fn_attrs = self.tcx.codegen_fn_attrs(item.id.def_id);
+ let codegen_fn_attrs = self.tcx.codegen_fn_attrs(item.id.owner_id);
let import_name_type = codegen_fn_attrs
.link_ordinal
.map_or(import_name_type, |ord| Some(PeImportNameType::Ordinal(ord)));
import_name_type,
calling_convention,
span: item.span,
- is_fn: self.tcx.def_kind(item.id.def_id).is_fn_like(),
+ is_fn: self.tcx.def_kind(item.id.owner_id).is_fn_like(),
}
}
}
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash};
use rustc_hir::diagnostic_items::DiagnosticItems;
-use rustc_hir::lang_items;
use rustc_index::vec::{Idx, IndexVec};
use rustc_middle::metadata::ModChild;
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
}
fn opt_item_name(self, item_index: DefIndex) -> Option<Symbol> {
- self.def_key(item_index).disambiguated_data.data.get_opt_name()
+ let def_key = self.def_key(item_index);
+ def_key.disambiguated_data.data.get_opt_name().or_else(|| {
+ if def_key.disambiguated_data.data == DefPathData::Ctor {
+ let parent_index = def_key.parent.expect("no parent for a constructor");
+ self.def_key(parent_index).disambiguated_data.data.get_opt_name()
+ } else {
+ None
+ }
+ })
}
fn item_name(self, item_index: DefIndex) -> Symbol {
.get(self, item_id)
.unwrap_or_else(LazyArray::empty)
.decode(self)
- .map(|index| self.get_variant(&self.def_kind(index), index, did))
+ .filter_map(|index| {
+ let kind = self.def_kind(index);
+ match kind {
+ DefKind::Ctor(..) => None,
+ _ => Some(self.get_variant(&kind, index, did)),
+ }
+ })
.collect()
} else {
std::iter::once(self.get_variant(&kind, item_id, did)).collect()
}
/// Iterates over the language items in the given crate.
- fn get_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] {
+ fn get_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, LangItem)] {
tcx.arena.alloc_from_iter(
self.root
.lang_items
callback(ModChild { ident, res, vis, span, macro_rules });
- // For non-re-export structs and variants add their constructors to children.
- // Re-export lists automatically contain constructors when necessary.
- match kind {
- DefKind::Struct => {
- if let Some((ctor_def_id, ctor_kind)) =
- self.get_ctor_def_id_and_kind(child_index)
- {
- let ctor_res =
- Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id);
- let vis = self.get_visibility(ctor_def_id.index);
- callback(ModChild {
- ident,
- res: ctor_res,
- vis,
- span,
- macro_rules: false,
- });
- }
- }
- DefKind::Variant => {
- // Braced variants, unlike structs, generate unusable names in
- // value namespace, they are reserved for possible future use.
- // It's ok to use the variant's id as a ctor id since an
- // error will be reported on any use of such resolution anyway.
- let (ctor_def_id, ctor_kind) = self
- .get_ctor_def_id_and_kind(child_index)
- .unwrap_or((def_id, CtorKind::Fictive));
- let ctor_res =
- Res::Def(DefKind::Ctor(CtorOf::Variant, ctor_kind), ctor_def_id);
- let mut vis = self.get_visibility(ctor_def_id.index);
- if ctor_def_id == def_id && vis.is_public() {
- // For non-exhaustive variants lower the constructor visibility to
- // within the crate. We only need this for fictive constructors,
- // for other constructors correct visibilities
- // were already encoded in metadata.
- let mut attrs = self.get_item_attrs(def_id.index, sess);
- if attrs.any(|item| item.has_name(sym::non_exhaustive)) {
- let crate_def_id = self.local_def_id(CRATE_DEF_INDEX);
- vis = ty::Visibility::Restricted(crate_def_id);
- }
+ // For non-reexport variants add their fictive constructors to children.
+ // Braced variants, unlike structs, generate unusable names in value namespace,
+ // they are reserved for possible future use. It's ok to use the variant's id as
+ // a ctor id since an error will be reported on any use of such resolution anyway.
+ // Reexport lists automatically contain such constructors when necessary.
+ if kind == DefKind::Variant && self.get_ctor_def_id_and_kind(child_index).is_none()
+ {
+ let ctor_res =
+ Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fictive), def_id);
+ let mut vis = vis;
+ if vis.is_public() {
+ // For non-exhaustive variants lower the constructor visibility to
+ // within the crate. We only need this for fictive constructors,
+ // for other constructors correct visibilities
+ // were already encoded in metadata.
+ let mut attrs = self.get_item_attrs(def_id.index, sess);
+ if attrs.any(|item| item.has_name(sym::non_exhaustive)) {
+ vis = ty::Visibility::Restricted(self.local_def_id(CRATE_DEF_INDEX));
}
- callback(ModChild { ident, res: ctor_res, vis, span, macro_rules: false });
}
- _ => {}
+ callback(ModChild { ident, res: ctor_res, vis, span, macro_rules: false });
}
}
}
)
}
- fn get_missing_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [lang_items::LangItem] {
+ fn get_missing_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [LangItem] {
tcx.arena.alloc_from_iter(self.root.lang_items_missing.decode(self))
}
self.root.has_global_allocator
}
+ pub(crate) fn has_alloc_error_handler(&self) -> bool {
+ self.root.has_alloc_error_handler
+ }
+
pub(crate) fn has_default_lib_allocator(&self) -> bool {
self.root.has_default_lib_allocator
}
is_panic_runtime => { cdata.root.panic_runtime }
is_compiler_builtins => { cdata.root.compiler_builtins }
has_global_allocator => { cdata.root.has_global_allocator }
+ has_alloc_error_handler => { cdata.root.has_alloc_error_handler }
has_panic_handler => { cdata.root.has_panic_handler }
is_profiler_runtime => { cdata.root.profiler_runtime }
required_panic_strategy => { cdata.root.required_panic_strategy }
// resolve! Does this work? Unsure! That's what the issue is about
*providers = Providers {
allocator_kind: |tcx, ()| CStore::from_tcx(tcx).allocator_kind(),
+ alloc_error_handler_kind: |tcx, ()| CStore::from_tcx(tcx).alloc_error_handler_kind(),
is_private_dep: |_tcx, cnum| {
assert_eq!(cnum, LOCAL_CRATE);
false
assert_eq!(cnum, LOCAL_CRATE);
CStore::from_tcx(tcx).has_global_allocator()
},
+ has_alloc_error_handler: |tcx, cnum| {
+ assert_eq!(cnum, LOCAL_CRATE);
+ CStore::from_tcx(tcx).has_alloc_error_handler()
+ },
postorder_cnums: |tcx, ()| {
tcx.arena
.alloc_slice(&CStore::from_tcx(tcx).crate_dependencies_in_postorder(LOCAL_CRATE))
};
use rustc_hir::definitions::DefPathData;
use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::lang_items;
+use rustc_hir::lang_items::LangItem;
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::dependency_format::Linkage;
use rustc_middle::middle::exported_symbols::{
panic_in_drop_strategy: tcx.sess.opts.unstable_opts.panic_in_drop,
edition: tcx.sess.edition(),
has_global_allocator: tcx.has_global_allocator(LOCAL_CRATE),
+ has_alloc_error_handler: tcx.has_alloc_error_handler(LOCAL_CRATE),
has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE),
has_default_lib_allocator: tcx
.sess
} else if attr.doc_str().is_some() {
// We keep all public doc comments because they might be "imported" into downstream crates
// if they use `#[doc(inline)]` to copy an item's documentation into their own.
- *is_def_id_public.get_or_insert_with(|| {
- tcx.privacy_access_levels(()).get_effective_vis(def_id).is_some()
- })
+ *is_def_id_public.get_or_insert_with(|| tcx.effective_visibilities(()).is_exported(def_id))
} else if attr.has_name(sym::doc) {
// If this is a `doc` attribute, and it's marked `inline` (as in `#[doc(inline)]`), we can
// remove it. It won't be inlinable in downstream crates.
// from name resolution point of view.
hir::ItemKind::ForeignMod { items, .. } => {
for foreign_item in items {
- yield foreign_item.id.def_id.def_id.local_def_index;
+ yield foreign_item.id.owner_id.def_id.local_def_index;
}
}
// Only encode named non-reexport children, reexports are encoded
// separately and unnamed items are not used by name resolution.
hir::ItemKind::ExternCrate(..) => continue,
- _ if tcx.def_key(item_id.def_id.to_def_id()).get_opt_name().is_some() => {
- yield item_id.def_id.def_id.local_def_index;
+ hir::ItemKind::Struct(ref vdata, _) => {
+ yield item_id.owner_id.def_id.local_def_index;
+ // Encode constructors which take a separate slot in value namespace.
+ if let Some(ctor_hir_id) = vdata.ctor_hir_id() {
+ yield tcx.hir().local_def_id(ctor_hir_id).local_def_index;
+ }
+ }
+ _ if tcx.def_key(item_id.owner_id.to_def_id()).get_opt_name().is_some() => {
+ yield item_id.owner_id.def_id.local_def_index;
}
_ => continue,
}
record!(self.tables.macro_definition[def_id] <- &*macro_def.body);
}
hir::ItemKind::Mod(ref m) => {
- return self.encode_info_for_mod(item.def_id.def_id, m);
+ return self.encode_info_for_mod(item.owner_id.def_id, m);
}
hir::ItemKind::OpaqueTy(..) => {
self.encode_explicit_item_bounds(def_id);
};
// FIXME(eddyb) there should be a nicer way to do this.
match item.kind {
- hir::ItemKind::Enum(..) => record_array!(self.tables.children[def_id] <-
- self.tcx.adt_def(def_id).variants().iter().map(|v| {
- assert!(v.def_id.is_local());
- v.def_id.index
- })
- ),
+ hir::ItemKind::Enum(..) => {
+ record_array!(self.tables.children[def_id] <- iter::from_generator(||
+ for variant in tcx.adt_def(def_id).variants() {
+ yield variant.def_id.index;
+ // Encode constructors which take a separate slot in value namespace.
+ if let Some(ctor_def_id) = variant.ctor_def_id {
+ yield ctor_def_id.index;
+ }
+ }
+ ))
+ }
hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
record_array!(self.tables.children[def_id] <-
self.tcx.adt_def(def_id).non_enum_variant().fields.iter().map(|f| {
// normally in the visitor walk.
match item.kind {
hir::ItemKind::Enum(..) => {
- let def = self.tcx.adt_def(item.def_id.to_def_id());
+ let def = self.tcx.adt_def(item.owner_id.to_def_id());
for (i, variant) in def.variants().iter_enumerated() {
self.encode_enum_variant_info(def, i);
}
}
hir::ItemKind::Struct(ref struct_def, _) => {
- let def = self.tcx.adt_def(item.def_id.to_def_id());
+ let def = self.tcx.adt_def(item.owner_id.to_def_id());
// If the struct has a constructor, encode it.
if let Some(ctor_hir_id) = struct_def.ctor_hir_id() {
let ctor_def_id = self.tcx.hir().local_def_id(ctor_hir_id);
}
hir::ItemKind::Impl { .. } => {
for &trait_item_def_id in
- self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter()
+ self.tcx.associated_item_def_ids(item.owner_id.to_def_id()).iter()
{
self.encode_info_for_impl_item(trait_item_def_id);
}
}
hir::ItemKind::Trait(..) => {
- for &item_def_id in self.tcx.associated_item_def_ids(item.def_id.to_def_id()).iter()
+ for &item_def_id in
+ self.tcx.associated_item_def_ids(item.owner_id.to_def_id()).iter()
{
self.encode_info_for_trait_item(item_def_id);
}
self.lazy_array(diagnostic_items.iter().map(|(&name, def_id)| (name, def_id.index)))
}
- fn encode_lang_items(&mut self) -> LazyArray<(DefIndex, usize)> {
+ fn encode_lang_items(&mut self) -> LazyArray<(DefIndex, LangItem)> {
empty_proc_macro!(self);
- let tcx = self.tcx;
- let lang_items = tcx.lang_items();
- let lang_items = lang_items.items().iter();
- self.lazy_array(lang_items.enumerate().filter_map(|(i, &opt_def_id)| {
- if let Some(def_id) = opt_def_id {
- if def_id.is_local() {
- return Some((def_id.index, i));
- }
- }
- None
+ let lang_items = self.tcx.lang_items().iter();
+ self.lazy_array(lang_items.filter_map(|(lang_item, def_id)| {
+ def_id.as_local().map(|id| (id.local_def_index, lang_item))
}))
}
- fn encode_lang_items_missing(&mut self) -> LazyArray<lang_items::LangItem> {
+ fn encode_lang_items_missing(&mut self) -> LazyArray<LangItem> {
empty_proc_macro!(self);
let tcx = self.tcx;
self.lazy_array(&tcx.lang_items().missing)
FxHashMap::default();
for id in tcx.hir().items() {
- if matches!(tcx.def_kind(id.def_id), DefKind::Impl) {
- if let Some(trait_ref) = tcx.impl_trait_ref(id.def_id) {
+ if matches!(tcx.def_kind(id.owner_id), DefKind::Impl) {
+ if let Some(trait_ref) = tcx.impl_trait_ref(id.owner_id) {
let simplified_self_ty = fast_reject::simplify_type(
self.tcx,
trait_ref.self_ty(),
fx_hash_map
.entry(trait_ref.def_id)
.or_default()
- .push((id.def_id.def_id.local_def_index, simplified_self_ty));
+ .push((id.owner_id.def_id.local_def_index, simplified_self_ty));
}
}
}
intravisit::walk_item(self, item);
match item.kind {
hir::ItemKind::ExternCrate(_) | hir::ItemKind::Use(..) => {} // ignore these
- _ => self.encode_info_for_item(item.def_id.to_def_id(), item),
+ _ => self.encode_info_for_item(item.owner_id.to_def_id(), item),
}
}
fn visit_foreign_item(&mut self, ni: &'tcx hir::ForeignItem<'tcx>) {
intravisit::walk_foreign_item(self, ni);
- self.encode_info_for_foreign_item(ni.def_id.to_def_id(), ni);
+ self.encode_info_for_foreign_item(ni.owner_id.to_def_id(), ni);
}
fn visit_generics(&mut self, generics: &'tcx hir::Generics<'tcx>) {
intravisit::walk_generics(self, generics);
let mut traits = Vec::new();
for id in tcx.hir().items() {
- if matches!(tcx.def_kind(id.def_id), DefKind::Trait | DefKind::TraitAlias) {
- traits.push(id.def_id.to_def_id())
+ if matches!(tcx.def_kind(id.owner_id), DefKind::Trait | DefKind::TraitAlias) {
+ traits.push(id.owner_id.to_def_id())
}
}
use rustc_hir::def::{CtorKind, DefKind};
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, DefPathHash, StableCrateId};
use rustc_hir::definitions::DefKey;
-use rustc_hir::lang_items;
+use rustc_hir::lang_items::LangItem;
use rustc_index::bit_set::{BitSet, FiniteBitSet};
use rustc_index::vec::IndexVec;
use rustc_middle::metadata::ModChild;
panic_in_drop_strategy: PanicStrategy,
edition: Edition,
has_global_allocator: bool,
+ has_alloc_error_handler: bool,
has_panic_handler: bool,
has_default_lib_allocator: bool,
dylib_dependency_formats: LazyArray<Option<LinkagePreference>>,
lib_features: LazyArray<(Symbol, Option<Symbol>)>,
stability_implications: LazyArray<(Symbol, Symbol)>,
- lang_items: LazyArray<(DefIndex, usize)>,
- lang_items_missing: LazyArray<lang_items::LangItem>,
+ lang_items: LazyArray<(DefIndex, LangItem)>,
+ lang_items_missing: LazyArray<LangItem>,
diagnostic_items: LazyArray<(Symbol, DefIndex)>,
native_libraries: LazyArray<NativeLib>,
foreign_modules: LazyArray<ForeignModule>,
rustc_target = { path = "../rustc_target" }
rustc_type_ir = { path = "../rustc_type_ir" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
-thin-vec = "0.2.8"
+thin-vec = "0.2.9"
tracing = "0.1"
[features]
rustc_middle::infer::canonical::QueryResponse<'tcx, rustc_middle::ty::Ty<'tcx>>
>,
[] all_traits: Vec<rustc_hir::def_id::DefId>,
- [] privacy_access_levels: rustc_middle::middle::privacy::AccessLevels,
+ [] effective_visibilities: rustc_middle::middle::privacy::EffectiveVisibilities,
[] foreign_module: rustc_session::cstore::ForeignModule,
[] foreign_modules: Vec<rustc_session::cstore::ForeignModule>,
[] upvars_mentioned: rustc_data_structures::fx::FxIndexMap<rustc_hir::HirId, rustc_hir::Upvar>,
// since we need to allocate this type on both the `rustc_hir` arena
// (during lowering) and the `librustc_middle` arena (for decoding MIR)
[decode] asm_template: rustc_ast::InlineAsmTemplatePiece,
- [decode] used_trait_imports: rustc_data_structures::fx::FxHashSet<rustc_hir::def_id::LocalDefId>,
+ [decode] used_trait_imports: rustc_data_structures::unord::UnordSet<rustc_hir::def_id::LocalDefId>,
[decode] is_late_bound_map: rustc_data_structures::fx::FxIndexSet<rustc_hir::def_id::LocalDefId>,
[decode] impl_source: rustc_middle::traits::ImplSource<'tcx, ()>,
#[primary_span]
pub span: Span,
}
+
+#[derive(Diagnostic)]
+#[diag(middle_strict_coherence_needs_negative_coherence)]
+pub(crate) struct StrictCoherenceNeedsNegativeCoherence {
+ #[primary_span]
+ pub span: Span,
+ #[label]
+ pub attr_span: Option<Span>,
+}
}
pub fn item(self, id: ItemId) -> &'hir Item<'hir> {
- self.tcx.hir_owner(id.def_id).unwrap().node.expect_item()
+ self.tcx.hir_owner(id.owner_id).unwrap().node.expect_item()
}
pub fn trait_item(self, id: TraitItemId) -> &'hir TraitItem<'hir> {
- self.tcx.hir_owner(id.def_id).unwrap().node.expect_trait_item()
+ self.tcx.hir_owner(id.owner_id).unwrap().node.expect_trait_item()
}
pub fn impl_item(self, id: ImplItemId) -> &'hir ImplItem<'hir> {
- self.tcx.hir_owner(id.def_id).unwrap().node.expect_impl_item()
+ self.tcx.hir_owner(id.owner_id).unwrap().node.expect_impl_item()
}
pub fn foreign_item(self, id: ForeignItemId) -> &'hir ForeignItem<'hir> {
- self.tcx.hir_owner(id.def_id).unwrap().node.expect_foreign_item()
+ self.tcx.hir_owner(id.owner_id).unwrap().node.expect_foreign_item()
}
pub fn body(self, id: BodyId) -> &'hir Body<'hir> {
fn visit_item(&mut self, item: &'hir Item<'hir>) {
if associated_body(Node::Item(item)).is_some() {
- self.body_owners.push(item.def_id.def_id);
+ self.body_owners.push(item.owner_id.def_id);
}
self.items.push(item.item_id());
// Items that are modules are handled here instead of in visit_mod.
if let ItemKind::Mod(module) = &item.kind {
- self.submodules.push(item.def_id);
+ self.submodules.push(item.owner_id);
// A module collector does not recurse inside nested modules.
if self.crate_collector {
intravisit::walk_mod(self, module, item.hir_id());
fn visit_trait_item(&mut self, item: &'hir TraitItem<'hir>) {
if associated_body(Node::TraitItem(item)).is_some() {
- self.body_owners.push(item.def_id.def_id);
+ self.body_owners.push(item.owner_id.def_id);
}
self.trait_items.push(item.trait_item_id());
fn visit_impl_item(&mut self, item: &'hir ImplItem<'hir>) {
if associated_body(Node::ImplItem(item)).is_some() {
- self.body_owners.push(item.def_id.def_id);
+ self.body_owners.push(item.owner_id.def_id);
}
self.impl_items.push(item.impl_item_id());
pub fn definitions(&self) -> impl Iterator<Item = LocalDefId> + '_ {
self.items
.iter()
- .map(|id| id.def_id.def_id)
- .chain(self.trait_items.iter().map(|id| id.def_id.def_id))
- .chain(self.impl_items.iter().map(|id| id.def_id.def_id))
- .chain(self.foreign_items.iter().map(|id| id.def_id.def_id))
+ .map(|id| id.owner_id.def_id)
+ .chain(self.trait_items.iter().map(|id| id.owner_id.def_id))
+ .chain(self.impl_items.iter().map(|id| id.owner_id.def_id))
+ .chain(self.foreign_items.iter().map(|id| id.owner_id.def_id))
}
pub fn par_items(&self, f: impl Fn(ItemId) + Send + Sync) {
}
}
-pub type QueryOutlivesConstraint<'tcx> =
- (ty::Binder<'tcx, ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>, ConstraintCategory);
+pub type QueryOutlivesConstraint<'tcx> = (
+ ty::Binder<'tcx, ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>>,
+ ConstraintCategory<'tcx>,
+);
TrivialTypeTraversalAndLiftImpls! {
for <'tcx> {
tcx.mk_ty(ty::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i).into())).into()
}
GenericArgKind::Lifetime(..) => {
- let br =
- ty::BoundRegion { var: ty::BoundVar::from_u32(i), kind: ty::BrAnon(i) };
+ let br = ty::BoundRegion {
+ var: ty::BoundVar::from_u32(i),
+ kind: ty::BrAnon(i, None),
+ };
tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
}
GenericArgKind::Const(ct) => tcx
- .mk_const(ty::ConstS {
- ty: ct.ty(),
- kind: ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i)),
- })
+ .mk_const(
+ ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from_u32(i)),
+ ct.ty(),
+ )
.into(),
})
.collect(),
/// The innermost function for emitting lints.
///
-/// If you are loocking to implement a lint, look for higher level functions,
+/// If you are looking to implement a lint, look for higher level functions,
/// for example:
/// - [`TyCtxt::emit_spanned_lint`]
/// - [`TyCtxt::struct_span_lint_hir`]
_ => None,
}
}
-
- pub fn is_weak_lang_item(self, item_def_id: DefId) -> bool {
- self.lang_items().is_weak_lang_item(item_def_id)
- }
}
/// Returns `true` if the specified `lang_item` must be present for this
//! A pass that checks to make sure private fields and methods aren't used
//! outside their scopes. This pass will also generate a set of exported items
//! which are available for use externally when compiled as a library.
-use crate::ty::{DefIdTree, Visibility};
+use crate::ty::{DefIdTree, TyCtxt, Visibility};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_hir::def::DefKind;
use rustc_macros::HashStable;
use rustc_query_system::ich::StableHashingContext;
-use rustc_span::def_id::{DefId, LocalDefId};
+use rustc_span::def_id::LocalDefId;
use std::hash::Hash;
-/// Represents the levels of accessibility an item can have.
+/// Represents the levels of effective visibility an item can have.
///
-/// The variants are sorted in ascending order of accessibility.
+/// The variants are sorted in ascending order of directness.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, HashStable)]
-pub enum AccessLevel {
- /// Superset of `AccessLevel::Reachable` used to mark impl Trait items.
- ReachableFromImplTrait,
- /// Exported items + items participating in various kinds of public interfaces,
- /// but not directly nameable. For example, if function `fn f() -> T {...}` is
- /// public, then type `T` is reachable. Its values can be obtained by other crates
- /// even if the type itself is not nameable.
+pub enum Level {
+ /// Superset of `Reachable` including items leaked through return position `impl Trait`.
+ ReachableThroughImplTrait,
+ /// Item is either reexported, or leaked through any kind of interface.
+ /// For example, if function `fn f() -> T {...}` is directly public, then type `T` is publicly
+ /// reachable and its values can be obtained by other crates even if the type itself is not
+ /// nameable.
Reachable,
- /// Public items + items accessible to other crates with the help of `pub use` re-exports.
- Exported,
- /// Items accessible to other crates directly, without the help of re-exports.
- Public,
+ /// Item is accessible either directly, or with help of `use` reexports.
+ Reexported,
+ /// Item is directly accessible, without help of reexports.
+ Direct,
}
-impl AccessLevel {
- pub fn all_levels() -> [AccessLevel; 4] {
- [
- AccessLevel::Public,
- AccessLevel::Exported,
- AccessLevel::Reachable,
- AccessLevel::ReachableFromImplTrait,
- ]
+impl Level {
+ pub fn all_levels() -> [Level; 4] {
+ [Level::Direct, Level::Reexported, Level::Reachable, Level::ReachableThroughImplTrait]
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)]
pub struct EffectiveVisibility {
- public: Visibility,
- exported: Visibility,
+ direct: Visibility,
+ reexported: Visibility,
reachable: Visibility,
- reachable_from_impl_trait: Visibility,
+ reachable_through_impl_trait: Visibility,
}
impl EffectiveVisibility {
- pub fn get(&self, tag: AccessLevel) -> &Visibility {
- match tag {
- AccessLevel::Public => &self.public,
- AccessLevel::Exported => &self.exported,
- AccessLevel::Reachable => &self.reachable,
- AccessLevel::ReachableFromImplTrait => &self.reachable_from_impl_trait,
+ pub fn at_level(&self, level: Level) -> &Visibility {
+ match level {
+ Level::Direct => &self.direct,
+ Level::Reexported => &self.reexported,
+ Level::Reachable => &self.reachable,
+ Level::ReachableThroughImplTrait => &self.reachable_through_impl_trait,
}
}
- fn get_mut(&mut self, tag: AccessLevel) -> &mut Visibility {
- match tag {
- AccessLevel::Public => &mut self.public,
- AccessLevel::Exported => &mut self.exported,
- AccessLevel::Reachable => &mut self.reachable,
- AccessLevel::ReachableFromImplTrait => &mut self.reachable_from_impl_trait,
+ fn at_level_mut(&mut self, level: Level) -> &mut Visibility {
+ match level {
+ Level::Direct => &mut self.direct,
+ Level::Reexported => &mut self.reexported,
+ Level::Reachable => &mut self.reachable,
+ Level::ReachableThroughImplTrait => &mut self.reachable_through_impl_trait,
}
}
- pub fn is_public_at_level(&self, tag: AccessLevel) -> bool {
- self.get(tag).is_public()
+ pub fn is_public_at_level(&self, level: Level) -> bool {
+ self.at_level(level).is_public()
}
pub fn from_vis(vis: Visibility) -> EffectiveVisibility {
EffectiveVisibility {
- public: vis,
- exported: vis,
+ direct: vis,
+ reexported: vis,
reachable: vis,
- reachable_from_impl_trait: vis,
+ reachable_through_impl_trait: vis,
}
}
}
-/// Holds a map of accessibility levels for reachable HIR nodes.
-#[derive(Debug, Clone)]
-pub struct AccessLevels<Id = LocalDefId> {
+/// Holds a map of effective visibilities for reachable HIR nodes.
+#[derive(Clone, Debug)]
+pub struct EffectiveVisibilities<Id = LocalDefId> {
map: FxHashMap<Id, EffectiveVisibility>,
}
-impl<Id: Hash + Eq + Copy> AccessLevels<Id> {
- pub fn is_public_at_level(&self, id: Id, tag: AccessLevel) -> bool {
- self.get_effective_vis(id)
- .map_or(false, |effective_vis| effective_vis.is_public_at_level(tag))
+impl EffectiveVisibilities {
+ pub fn is_public_at_level(&self, id: LocalDefId, level: Level) -> bool {
+ self.effective_vis(id)
+ .map_or(false, |effective_vis| effective_vis.is_public_at_level(level))
}
- /// See `AccessLevel::Reachable`.
- pub fn is_reachable(&self, id: Id) -> bool {
- self.is_public_at_level(id, AccessLevel::Reachable)
+ /// See `Level::Reachable`.
+ pub fn is_reachable(&self, id: LocalDefId) -> bool {
+ self.is_public_at_level(id, Level::Reachable)
}
- /// See `AccessLevel::Exported`.
- pub fn is_exported(&self, id: Id) -> bool {
- self.is_public_at_level(id, AccessLevel::Exported)
+ /// See `Level::Reexported`.
+ pub fn is_exported(&self, id: LocalDefId) -> bool {
+ self.is_public_at_level(id, Level::Reexported)
}
- /// See `AccessLevel::Public`.
- pub fn is_public(&self, id: Id) -> bool {
- self.is_public_at_level(id, AccessLevel::Public)
+ /// See `Level::Direct`.
+ pub fn is_directly_public(&self, id: LocalDefId) -> bool {
+ self.is_public_at_level(id, Level::Direct)
}
- pub fn get_access_level(&self, id: Id) -> Option<AccessLevel> {
- self.get_effective_vis(id).and_then(|effective_vis| {
- for level in AccessLevel::all_levels() {
+ pub fn public_at_level(&self, id: LocalDefId) -> Option<Level> {
+ self.effective_vis(id).and_then(|effective_vis| {
+ for level in Level::all_levels() {
if effective_vis.is_public_at_level(level) {
return Some(level);
}
})
}
- pub fn get_effective_vis(&self, id: Id) -> Option<&EffectiveVisibility> {
- self.map.get(&id)
- }
-
- pub fn iter(&self) -> impl Iterator<Item = (&Id, &EffectiveVisibility)> {
- self.map.iter()
- }
-
- pub fn map_id<OutId: Hash + Eq + Copy>(&self, f: impl Fn(Id) -> OutId) -> AccessLevels<OutId> {
- AccessLevels { map: self.map.iter().map(|(k, v)| (f(*k), *v)).collect() }
+ // FIXME: Share code with `fn update`.
+ pub fn update_eff_vis(
+ &mut self,
+ def_id: LocalDefId,
+ eff_vis: &EffectiveVisibility,
+ tree: impl DefIdTree,
+ ) {
+ use std::collections::hash_map::Entry;
+ match self.map.entry(def_id) {
+ Entry::Occupied(mut occupied) => {
+ let old_eff_vis = occupied.get_mut();
+ for l in Level::all_levels() {
+ let vis_at_level = eff_vis.at_level(l);
+ let old_vis_at_level = old_eff_vis.at_level_mut(l);
+ if vis_at_level != old_vis_at_level
+ && vis_at_level.is_at_least(*old_vis_at_level, tree)
+ {
+ *old_vis_at_level = *vis_at_level
+ }
+ }
+ old_eff_vis
+ }
+ Entry::Vacant(vacant) => vacant.insert(*eff_vis),
+ };
}
- pub fn set_access_level(
+ pub fn set_public_at_level(
&mut self,
- id: Id,
+ id: LocalDefId,
default_vis: impl FnOnce() -> Visibility,
- tag: AccessLevel,
+ level: Level,
) {
let mut effective_vis = self
- .get_effective_vis(id)
+ .effective_vis(id)
.copied()
.unwrap_or_else(|| EffectiveVisibility::from_vis(default_vis()));
- for level in AccessLevel::all_levels() {
- if level <= tag {
- *effective_vis.get_mut(level) = Visibility::Public;
+ for l in Level::all_levels() {
+ if l <= level {
+ *effective_vis.at_level_mut(l) = Visibility::Public;
}
}
self.map.insert(id, effective_vis);
}
+
+ pub fn check_invariants(&self, tcx: TyCtxt<'_>, early: bool) {
+ if !cfg!(debug_assertions) {
+ return;
+ }
+ for (&def_id, ev) in &self.map {
+ // More direct visibility levels can never go farther than less direct ones,
+ // neither of effective visibilities can go farther than nominal visibility,
+ // and all effective visibilities are larger or equal than private visibility.
+ let private_vis = Visibility::Restricted(tcx.parent_module_from_def_id(def_id));
+ let span = tcx.def_span(def_id.to_def_id());
+ if !ev.direct.is_at_least(private_vis, tcx) {
+ span_bug!(span, "private {:?} > direct {:?}", private_vis, ev.direct);
+ }
+ if !ev.reexported.is_at_least(ev.direct, tcx) {
+ span_bug!(span, "direct {:?} > reexported {:?}", ev.direct, ev.reexported);
+ }
+ if !ev.reachable.is_at_least(ev.reexported, tcx) {
+ span_bug!(span, "reexported {:?} > reachable {:?}", ev.reexported, ev.reachable);
+ }
+ if !ev.reachable_through_impl_trait.is_at_least(ev.reachable, tcx) {
+ span_bug!(
+ span,
+ "reachable {:?} > reachable_through_impl_trait {:?}",
+ ev.reachable,
+ ev.reachable_through_impl_trait
+ );
+ }
+ let nominal_vis = tcx.visibility(def_id);
+ let def_kind = tcx.opt_def_kind(def_id);
+ // FIXME: `rustc_privacy` is not yet updated for the new logic and can set
+ // effective visibilities that are larger than the nominal one.
+ if !nominal_vis.is_at_least(ev.reachable_through_impl_trait, tcx) && early {
+ span_bug!(
+ span,
+ "{:?}: reachable_through_impl_trait {:?} > nominal {:?}",
+ def_id,
+ ev.reachable_through_impl_trait,
+ nominal_vis
+ );
+ }
+ // Fully private items are never put into the table, this is important for performance.
+ // FIXME: Fully private `mod` items are currently put into the table.
+ if ev.reachable_through_impl_trait == private_vis && def_kind != Some(DefKind::Mod) {
+ span_bug!(span, "fully private item in the table {:?}: {:?}", def_id, ev.direct);
+ }
+ }
+ }
}
-impl<Id: Hash + Eq + Copy + Into<DefId>> AccessLevels<Id> {
+impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
+ pub fn iter(&self) -> impl Iterator<Item = (&Id, &EffectiveVisibility)> {
+ self.map.iter()
+ }
+
+ pub fn effective_vis(&self, id: Id) -> Option<&EffectiveVisibility> {
+ self.map.get(&id)
+ }
+
// `parent_id` is not necessarily a parent in source code tree,
// it is the node from which the maximum effective visibility is inherited.
pub fn update(
&mut self,
id: Id,
nominal_vis: Visibility,
- default_vis: impl FnOnce() -> Visibility,
- parent_id: Id,
- tag: AccessLevel,
+ default_vis: Visibility,
+ inherited_eff_vis: Option<EffectiveVisibility>,
+ level: Level,
tree: impl DefIdTree,
) -> bool {
let mut changed = false;
- let mut current_effective_vis = self.get_effective_vis(id).copied().unwrap_or_else(|| {
- if id.into().is_crate_root() {
- EffectiveVisibility::from_vis(Visibility::Public)
- } else {
- EffectiveVisibility::from_vis(default_vis())
- }
- });
- if let Some(inherited_effective_vis) = self.get_effective_vis(parent_id) {
- let mut inherited_effective_vis_at_prev_level = *inherited_effective_vis.get(tag);
+ let mut current_effective_vis = self
+ .map
+ .get(&id)
+ .copied()
+ .unwrap_or_else(|| EffectiveVisibility::from_vis(default_vis));
+ if let Some(inherited_effective_vis) = inherited_eff_vis {
+ let mut inherited_effective_vis_at_prev_level =
+ *inherited_effective_vis.at_level(level);
let mut calculated_effective_vis = inherited_effective_vis_at_prev_level;
- for level in AccessLevel::all_levels() {
- if tag >= level {
- let inherited_effective_vis_at_level = *inherited_effective_vis.get(level);
- let current_effective_vis_at_level = current_effective_vis.get_mut(level);
+ for l in Level::all_levels() {
+ if level >= l {
+ let inherited_effective_vis_at_level = *inherited_effective_vis.at_level(l);
+ let current_effective_vis_at_level = current_effective_vis.at_level_mut(l);
// effective visibility for id shouldn't be recalculated if
// inherited from parent_id effective visibility isn't changed at next level
if !(inherited_effective_vis_at_prev_level == inherited_effective_vis_at_level
- && tag != level)
+ && level != l)
{
calculated_effective_vis =
if nominal_vis.is_at_least(inherited_effective_vis_at_level, tree) {
}
}
-impl<Id> Default for AccessLevels<Id> {
+impl<Id> Default for EffectiveVisibilities<Id> {
fn default() -> Self {
- AccessLevels { map: Default::default() }
+ EffectiveVisibilities { map: Default::default() }
}
}
-impl<'a> HashStable<StableHashingContext<'a>> for AccessLevels {
+impl<'a> HashStable<StableHashingContext<'a>> for EffectiveVisibilities {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- let AccessLevels { ref map } = *self;
+ let EffectiveVisibilities { ref map } = *self;
map.hash_stable(hcx, hasher);
}
}
pub fn visitable(&self, index: usize) -> &dyn MirVisitable<'tcx> {
if index < self.statements.len() { &self.statements[index] } else { &self.terminator }
}
+
+ /// Does the block have no statements and an unreachable terminator?
+ pub fn is_empty_unreachable(&self) -> bool {
+ self.statements.is_empty() && matches!(self.terminator().kind, TerminatorKind::Unreachable)
+ }
}
impl<O> AssertKind<O> {
let generics = tcx.generics_of(item_def_id.to_def_id());
let index = generics.param_def_id_to_index[&def_id];
let name = tcx.hir().name(hir_id);
- let ty_const = tcx.mk_const(ty::ConstS {
- kind: ty::ConstKind::Param(ty::ParamConst::new(index, name)),
- ty,
- });
+ let ty_const =
+ tcx.mk_const(ty::ConstKind::Param(ty::ParamConst::new(index, name)), ty);
debug!(?ty_const);
return Self::Ty(ty_const);
/// `Location` represents the position of the start of the statement; or, if
/// `statement_index` equals the number of statements, then the start of the
/// terminator.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, HashStable, TyEncodable, TyDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Ord, PartialOrd, HashStable)]
pub struct Location {
/// The block that the location is within.
pub block: BasicBlock,
MonoItem::Fn(instance) => tcx.symbol_name(instance),
MonoItem::Static(def_id) => tcx.symbol_name(Instance::mono(tcx, def_id)),
MonoItem::GlobalAsm(item_id) => {
- SymbolName::new(tcx, &format!("global_asm_{:?}", item_id.def_id))
+ SymbolName::new(tcx, &format!("global_asm_{:?}", item_id.owner_id))
}
}
}
match *self {
MonoItem::Fn(Instance { def, .. }) => def.def_id().as_local(),
MonoItem::Static(def_id) => def_id.as_local(),
- MonoItem::GlobalAsm(item_id) => Some(item_id.def_id.def_id),
+ MonoItem::GlobalAsm(item_id) => Some(item_id.owner_id.def_id),
}
.map(|def_id| tcx.def_span(def_id))
}
}
}
MonoItem::Static(def_id) => def_id.as_local().map(Idx::index),
- MonoItem::GlobalAsm(item_id) => Some(item_id.def_id.def_id.index()),
+ MonoItem::GlobalAsm(item_id) => Some(item_id.owner_id.def_id.index()),
},
item.symbol_name(tcx),
)
use std::cell::Cell;
use std::fmt::{self, Debug};
-use super::{Field, Location, SourceInfo};
+use super::{Field, SourceInfo};
#[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)]
pub enum UnsafetyViolationKind {
pub blame_span: Span,
// ... due to this reason.
- pub category: ConstraintCategory,
+ pub category: ConstraintCategory<'tcx>,
}
// Make sure this enum doesn't unintentionally grow
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(ConstraintCategory, 16);
+rustc_data_structures::static_assert_size!(ConstraintCategory<'_>, 16);
/// Outlives-constraints can be categorized to determine whether and why they
/// are interesting (for error reporting). Order of variants indicates sort
///
/// See also `rustc_const_eval::borrow_check::constraints`.
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
-#[derive(TyEncodable, TyDecodable, HashStable)]
-pub enum ConstraintCategory {
+#[derive(TyEncodable, TyDecodable, HashStable, Lift, TypeVisitable, TypeFoldable)]
+pub enum ConstraintCategory<'tcx> {
Return(ReturnConstraint),
Yield,
UseAsConst,
ClosureBounds,
/// Contains the function type if available.
- CallArgument(Location),
+ CallArgument(Option<Ty<'tcx>>),
CopyBound,
SizedBound,
Assignment,
Internal,
}
-TrivialTypeTraversalAndLiftImpls! {
- ConstraintCategory,
-}
-
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
#[derive(TyEncodable, TyDecodable, HashStable, TypeVisitable, TypeFoldable)]
pub enum ReturnConstraint {
desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) }
}
+ /// Look up all native libraries this crate depends on.
+ /// These are assembled from the following places:
+ /// - `extern` blocks (depending on their `link` attributes)
+ /// - the `libs` (`-l`) option
query native_libraries(_: CrateNum) -> Vec<NativeLib> {
arena_cache
desc { "looking up the native libraries of a linked crate" }
cache_on_disk_if { true }
}
- query used_trait_imports(key: LocalDefId) -> &'tcx FxHashSet<LocalDefId> {
+ query used_trait_imports(key: LocalDefId) -> &'tcx UnordSet<LocalDefId> {
desc { |tcx| "finding used_trait_imports `{}`", tcx.def_path_str(key.to_def_id()) }
cache_on_disk_if { true }
}
cache_on_disk_if { key.is_local() }
}
- /// Performs part of the privacy check and computes "access levels".
- query privacy_access_levels(_: ()) -> &'tcx AccessLevels {
+ /// Performs part of the privacy check and computes effective visibilities.
+ query effective_visibilities(_: ()) -> &'tcx EffectiveVisibilities {
eval_always
- desc { "checking privacy access levels" }
+ desc { "checking effective visibilities" }
}
query check_private_in_public(_: ()) -> () {
eval_always
desc { "checking if the crate has_global_allocator" }
separate_provide_extern
}
+ query has_alloc_error_handler(_: CrateNum) -> bool {
+ // This query depends on untracked global state in CStore
+ eval_always
+ fatal_cycle
+ desc { "checking if the crate has_alloc_error_handler" }
+ separate_provide_extern
+ }
query has_panic_handler(_: CrateNum) -> bool {
fatal_cycle
desc { "checking if the crate has_panic_handler" }
desc { "available upstream drop-glue for `{:?}`", substs }
}
+ /// Returns a list of all `extern` blocks of a crate.
query foreign_modules(_: CrateNum) -> FxHashMap<DefId, ForeignModule> {
arena_cache
desc { "looking up the foreign modules of a linked crate" }
query entry_fn(_: ()) -> Option<(DefId, EntryFnType)> {
desc { "looking up the entry function of a crate" }
}
+
+ /// Finds the `rustc_proc_macro_decls` item of a crate.
query proc_macro_decls_static(_: ()) -> Option<LocalDefId> {
- desc { "looking up the derive registrar for a crate" }
+ desc { "looking up the proc macro declarations for a crate" }
}
+
// The macro which defines `rustc_metadata::provide_extern` depends on this query's name.
// Changing the name should cause a compiler error, but in case that changes, be aware.
query crate_hash(_: CrateNum) -> Svh {
desc { "looking up the hash a crate" }
separate_provide_extern
}
+
+ /// Gets the hash for the host proc macro. Used to support -Z dual-proc-macro.
query crate_host_hash(_: CrateNum) -> Option<Svh> {
eval_always
desc { "looking up the hash of a host version of a crate" }
separate_provide_extern
}
+
+ /// Gets the extra data to put in each output filename for a crate.
+ /// For example, compiling the `foo` crate with `extra-filename=-a` creates a `libfoo-b.rlib` file.
query extra_filename(_: CrateNum) -> String {
arena_cache
eval_always
desc { "looking up the extra filename for a crate" }
separate_provide_extern
}
+
+ /// Gets the paths where the crate came from in the file system.
query crate_extern_paths(_: CrateNum) -> Vec<PathBuf> {
arena_cache
eval_always
separate_provide_extern
}
+ /// Get the corresponding native library from the `native_libraries` query
query native_library(def_id: DefId) -> Option<&'tcx NativeLib> {
desc { |tcx| "getting the native library for `{}`", tcx.def_path_str(def_id) }
}
}
/// Returns the lang items defined in another crate by loading it from metadata.
- query defined_lang_items(_: CrateNum) -> &'tcx [(DefId, usize)] {
+ query defined_lang_items(_: CrateNum) -> &'tcx [(DefId, LangItem)] {
desc { "calculating the lang items defined in a crate" }
separate_provide_extern
}
eval_always
desc { "getting the allocator kind for the current crate" }
}
+ query alloc_error_handler_kind(_: ()) -> Option<AllocatorKind> {
+ eval_always
+ desc { "alloc error handler kind for the current crate" }
+ }
query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> {
desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) }
self
}
- pub fn to_constraint_category(&self) -> ConstraintCategory {
+ pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> {
match self.code() {
MatchImpl(cause, _) => cause.to_constraint_category(),
AscribeUserTypeProvePredicate(predicate_span) => {
pub substs: SubstsRef<'tcx>,
}
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift, Default)]
+#[derive(Clone, PartialEq, Eq, Hash, Lift, Default)]
pub struct InternedObligationCauseCode<'tcx> {
/// `None` for `ObligationCauseCode::MiscObligation` (a common case, occurs ~60% of
/// the time). `Some` otherwise.
code: Option<Lrc<ObligationCauseCode<'tcx>>>,
}
+impl<'tcx> std::fmt::Debug for InternedObligationCauseCode<'tcx> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let cause: &ObligationCauseCode<'_> = self;
+ cause.fmt(f)
+ }
+}
+
impl<'tcx> ObligationCauseCode<'tcx> {
#[inline(always)]
fn into(self) -> InternedObligationCauseCode<'tcx> {
},
AscribeUserTypeProvePredicate(Span),
+
+ RustCall,
}
/// The 'location' at which we try to perform HIR-based wf checking.
/// Signaling that an error has already been emitted, to avoid
/// multiple errors being shown.
ErrorReporting,
- /// Multiple applicable `impl`s where found. The `DefId`s correspond to
- /// all the `impl`s' Items.
- Ambiguous(Vec<DefId>),
}
/// When performing resolution, it is typically the case that there
+use crate::error::StrictCoherenceNeedsNegativeCoherence;
use crate::ty::fast_reject::SimplifiedType;
use crate::ty::visit::TypeVisitable;
use crate::ty::{self, TyCtxt};
if with_negative_coherence {
if strict_coherence { OverlapMode::Strict } else { OverlapMode::WithNegative }
- } else if strict_coherence {
- bug!("To use strict_coherence you need to set with_negative_coherence feature flag");
} else {
+ if strict_coherence {
+ let attr_span = trait_id
+ .as_local()
+ .into_iter()
+ .flat_map(|local_def_id| {
+ tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(local_def_id))
+ })
+ .find(|attr| attr.has_name(sym::rustc_strict_coherence))
+ .map(|attr| attr.span);
+ tcx.sess.emit_err(StrictCoherenceNeedsNegativeCoherence {
+ span: tcx.def_span(trait_id),
+ attr_span,
+ });
+ }
OverlapMode::Stable
}
}
if let Some(reported) = specialization_graph.has_errored {
Err(reported)
- } else if let Some(reported) = tcx.type_of(start_from_impl).error_reported() {
+ } else if let Err(reported) = tcx.type_of(start_from_impl).error_reported() {
Err(reported)
} else {
Ok(Ancestors {
//! A subset of a mir body used for const evaluatability checking.
use crate::mir;
use crate::ty::visit::TypeVisitable;
-use crate::ty::{self, DelaySpanBugEmitted, EarlyBinder, SubstsRef, Ty, TyCtxt};
+use crate::ty::{self, EarlyBinder, SubstsRef, Ty, TyCtxt};
use rustc_errors::ErrorGuaranteed;
use rustc_hir::def_id::DefId;
use std::cmp;
) -> Result<Option<AbstractConst<'tcx>>, ErrorGuaranteed> {
match ct.kind() {
ty::ConstKind::Unevaluated(uv) => AbstractConst::new(tcx, uv),
- ty::ConstKind::Error(DelaySpanBugEmitted { reported, .. }) => Err(reported),
+ ty::ConstKind::Error(reported) => Err(reported),
_ => Ok(None),
}
}
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Const<'tcx> {
fn decode(decoder: &mut D) -> Self {
- decoder.interner().mk_const(Decodable::decode(decoder))
+ let consts: ty::ConstS<'tcx> = Decodable::decode(decoder);
+ decoder.interner().mk_const(consts.kind, consts.ty)
}
}
match Self::try_eval_lit_or_param(tcx, ty, expr) {
Some(v) => v,
- None => tcx.mk_const(ty::ConstS {
- kind: ty::ConstKind::Unevaluated(ty::UnevaluatedConst {
+ None => tcx.mk_const(
+ ty::ConstKind::Unevaluated(ty::UnevaluatedConst {
def: def.to_global(),
substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
}),
ty,
- }),
+ ),
}
}
let generics = tcx.generics_of(item_def_id.to_def_id());
let index = generics.param_def_id_to_index[&def_id];
let name = tcx.hir().name(hir_id);
- Some(tcx.mk_const(ty::ConstS {
- kind: ty::ConstKind::Param(ty::ParamConst::new(index, name)),
- ty,
- }))
+ Some(tcx.mk_const(ty::ConstKind::Param(ty::ParamConst::new(index, name)), ty))
}
_ => None,
}
/// Interns the given value as a constant.
#[inline]
pub fn from_value(tcx: TyCtxt<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Self {
- tcx.mk_const(ConstS { kind: ConstKind::Value(val), ty })
+ tcx.mk_const(ConstKind::Value(val), ty)
}
/// Panics if self.kind != ty::ConstKind::Value
/// A placeholder for a const which could not be computed; this is
/// propagated to avoid useless error messages.
- Error(ty::DelaySpanBugEmitted),
+ Error(ErrorGuaranteed),
}
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{self, Lock, Lrc, ReadGuard, RwLock, WorkerLocal};
+use rustc_data_structures::unord::UnordSet;
use rustc_data_structures::vec_map::VecMap;
use rustc_errors::{
DecorateLint, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, MultiSpan,
type BoundTy = ty::BoundTy;
type PlaceholderType = ty::PlaceholderType;
type InferTy = InferTy;
- type DelaySpanBugEmitted = DelaySpanBugEmitted;
+ type ErrorGuaranteed = ErrorGuaranteed;
type PredicateKind = ty::PredicateKind<'tcx>;
type AllocId = crate::mir::interpret::AllocId;
type PlaceholderRegion = ty::PlaceholderRegion;
}
-/// A type that is not publicly constructable. This prevents people from making [`TyKind::Error`]s
-/// except through the error-reporting functions on a [`tcx`][TyCtxt].
-#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
-#[derive(TyEncodable, TyDecodable, HashStable)]
-pub struct DelaySpanBugEmitted {
- pub reported: ErrorGuaranteed,
- _priv: (),
-}
-
type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>;
pub struct CtxtInterners<'tcx> {
/// This is used for warning unused imports. During type
/// checking, this `Lrc` should not be cloned: it must have a ref-count
/// of 1 so that we can insert things into the set mutably.
- pub used_trait_imports: Lrc<FxHashSet<LocalDefId>>,
+ pub used_trait_imports: Lrc<UnordSet<LocalDefId>>,
/// If any errors occurred while type-checking this body,
/// this field will be set to `Some(ErrorGuaranteed)`.
}
}
+ /// Constructs a `TyKind::Error` type with current `ErrorGuaranteed`
+ #[track_caller]
+ pub fn ty_error_with_guaranteed(self, reported: ErrorGuaranteed) -> Ty<'tcx> {
+ self.mk_ty(Error(reported))
+ }
+
/// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used.
#[track_caller]
pub fn ty_error(self) -> Ty<'tcx> {
#[track_caller]
pub fn ty_error_with_message<S: Into<MultiSpan>>(self, span: S, msg: &str) -> Ty<'tcx> {
let reported = self.sess.delay_span_bug(span, msg);
- self.mk_ty(Error(DelaySpanBugEmitted { reported, _priv: () }))
+ self.mk_ty(Error(reported))
+ }
+
+ /// Like [TyCtxt::ty_error] but for constants, with current `ErrorGuaranteed`
+ #[track_caller]
+ pub fn const_error_with_guaranteed(
+ self,
+ ty: Ty<'tcx>,
+ reported: ErrorGuaranteed,
+ ) -> Const<'tcx> {
+ self.mk_const(ty::ConstKind::Error(reported), ty)
}
/// Like [TyCtxt::ty_error] but for constants.
msg: &str,
) -> Const<'tcx> {
let reported = self.sess.delay_span_bug(span, msg);
- self.mk_const(ty::ConstS {
- kind: ty::ConstKind::Error(DelaySpanBugEmitted { reported, _priv: () }),
- ty,
- })
+ self.mk_const(ty::ConstKind::Error(reported), ty)
}
pub fn consider_optimizing<T: Fn() -> String>(self, msg: T) -> bool {
direct_interners! {
region: mk_region(RegionKind<'tcx>): Region -> Region<'tcx>,
- const_: mk_const(ConstS<'tcx>): Const -> Const<'tcx>,
+ const_: mk_const_internal(ConstS<'tcx>): Const -> Const<'tcx>,
const_allocation: intern_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>,
layout: intern_layout(LayoutS<'tcx>): Layout -> Layout<'tcx>,
adt_def: intern_adt_def(AdtDefData): AdtDef -> AdtDef<'tcx>,
#[inline]
pub fn mk_lang_item(self, ty: Ty<'tcx>, item: LangItem) -> Option<Ty<'tcx>> {
- let def_id = self.lang_items().require(item).ok()?;
+ let def_id = self.lang_items().get(item)?;
Some(self.mk_generic_adt(def_id, ty))
}
self.mk_ty_infer(TyVar(v))
}
+ #[inline]
+ pub fn mk_const(self, kind: ty::ConstKind<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
+ self.mk_const_internal(ty::ConstS { kind, ty })
+ }
+
#[inline]
pub fn mk_const_var(self, v: ConstVid<'tcx>, ty: Ty<'tcx>) -> Const<'tcx> {
- self.mk_const(ty::ConstS { kind: ty::ConstKind::Infer(InferConst::Var(v)), ty })
+ self.mk_const(ty::ConstKind::Infer(InferConst::Var(v)), ty)
}
#[inline]
#[inline]
pub fn mk_const_infer(self, ic: InferConst<'tcx>, ty: Ty<'tcx>) -> ty::Const<'tcx> {
- self.mk_const(ty::ConstS { kind: ty::ConstKind::Infer(ic), ty })
+ self.mk_const(ty::ConstKind::Infer(ic), ty)
}
#[inline]
#[inline]
pub fn mk_const_param(self, index: u32, name: Symbol, ty: Ty<'tcx>) -> Const<'tcx> {
- self.mk_const(ty::ConstS { kind: ty::ConstKind::Param(ParamConst { index, name }), ty })
+ self.mk_const(ty::ConstKind::Param(ParamConst { index, name }), ty)
}
pub fn mk_param_from_def(self, param: &ty::GenericParamDef) -> GenericArg<'tcx> {
span: impl Into<MultiSpan>,
decorator: impl for<'a> DecorateLint<'a, ()>,
) {
- self.struct_span_lint_hir(lint, hir_id, span, decorator.msg(), |diag| {
+ let msg = decorator.msg();
+ let (level, src) = self.lint_level_at_node(lint, hir_id);
+ struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg, |diag| {
decorator.decorate_lint(diag)
})
}
/// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
///
/// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
+ #[rustc_lint_diagnostics]
pub fn struct_span_lint_hir(
self,
lint: &'static Lint,
/// Return value of the `decorate` closure is ignored, see [`struct_lint_level`] for a detailed explanation.
///
/// [`struct_lint_level`]: rustc_middle::lint::struct_lint_level#decorate-signature
+ #[rustc_lint_diagnostics]
pub fn struct_lint_node(
self,
lint: &'static Lint,
(ty::Projection(_), ty::Projection(_)) => {
diag.note("an associated type was expected, but a different one was found");
}
- (ty::Param(p), ty::Projection(proj)) | (ty::Projection(proj), ty::Param(p)) => {
+ (ty::Param(p), ty::Projection(proj)) | (ty::Projection(proj), ty::Param(p))
+ if self.def_kind(proj.item_def_id) != DefKind::ImplTraitPlaceholder =>
+ {
let generics = self.generics_of(body_owner_def_id);
let p_span = self.def_span(generics.type_param(p, self).def_id);
if !sp.contains(p_span) {
// FIXME: account for returning some type in a trait fn impl that has
// an assoc type as a return type (#72076).
if let hir::Defaultness::Default { has_value: true } =
- self.impl_defaultness(item.id.def_id)
+ self.impl_defaultness(item.id.owner_id)
{
- if self.type_of(item.id.def_id) == found {
+ if self.type_of(item.id.owner_id) == found {
diag.span_label(
item.span,
"associated type defaults can't be assumed inside the \
})) => {
for item in &items[..] {
if let hir::AssocItemKind::Type = item.kind {
- if self.type_of(item.id.def_id) == found {
+ if self.type_of(item.id.owner_id) == found {
diag.span_label(item.span, "expected this associated type");
return true;
}
))
},
consts: &mut |c, ty: Ty<'tcx>| {
- self.mk_const(ty::ConstS {
- kind: ty::ConstKind::Bound(ty::INNERMOST, shift_bv(c)),
- ty,
- })
+ self.mk_const(ty::ConstKind::Bound(ty::INNERMOST, shift_bv(c)), ty)
},
},
)
.replace_late_bound_regions(sig, |_| {
let br = ty::BoundRegion {
var: ty::BoundVar::from_u32(counter),
- kind: ty::BrAnon(counter),
+ kind: ty::BrAnon(counter, None),
};
let r = self.mk_region(ty::ReLateBound(ty::INNERMOST, br));
counter += 1;
})
.0;
let bound_vars = self.mk_bound_variable_kinds(
- (0..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i))),
+ (0..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i, None))),
);
Binder::bind_with_vars(inner, bound_vars)
}
let index = entry.index();
let var = ty::BoundVar::from_usize(index);
let kind = entry
- .or_insert_with(|| ty::BoundVariableKind::Region(ty::BrAnon(index as u32)))
+ .or_insert_with(|| {
+ ty::BoundVariableKind::Region(ty::BrAnon(index as u32, None))
+ })
.expect_region();
let br = ty::BoundRegion { var, kind };
self.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br))
let index = entry.index();
let var = ty::BoundVar::from_usize(index);
let () = entry.or_insert_with(|| ty::BoundVariableKind::Const).expect_const();
- self.tcx.mk_const(ty::ConstS { ty, kind: ty::ConstKind::Bound(ty::INNERMOST, var) })
+ self.tcx.mk_const(ty::ConstKind::Bound(ty::INNERMOST, var), ty)
}
}
ct
} else {
let debruijn = debruijn.shifted_in(self.amount);
- self.tcx.mk_const(ty::ConstS {
- kind: ty::ConstKind::Bound(debruijn, bound_ct),
- ty: ct.ty(),
- })
+ self.tcx.mk_const(ty::ConstKind::Bound(debruijn, bound_ct), ct.ty())
}
} else {
ct.super_fold_with(self)
Instance::resolve(tcx, ty::ParamEnv::reveal_all(), def_id, substs).unwrap().unwrap()
}
+ #[instrument(level = "debug", skip(tcx), ret)]
pub fn fn_once_adapter_instance(
tcx: TyCtxt<'tcx>,
closure_did: DefId,
substs: ty::SubstsRef<'tcx>,
) -> Option<Instance<'tcx>> {
- debug!("fn_once_adapter_shim({:?}, {:?})", closure_did, substs);
let fn_once = tcx.require_lang_item(LangItem::FnOnce, None);
let call_once = tcx
.associated_items(fn_once)
assert_eq!(sig.inputs().len(), 1);
let substs = tcx.mk_substs_trait(self_ty, &[sig.inputs()[0].into()]);
- debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig);
+ debug!(?self_ty, ?sig);
Some(Instance { def, substs })
}
} else {
match mt {
hir::Mutability::Not => {
- if ty.is_freeze(tcx.at(DUMMY_SP), cx.param_env()) {
+ if ty.is_freeze(tcx, cx.param_env()) {
PointerKind::Frozen
} else {
PointerKind::SharedMutable
// noalias, as another pointer to the structure can be obtained, that
// is not based-on the original reference. We consider all !Unpin
// types to be potentially self-referential here.
- if ty.is_unpin(tcx.at(DUMMY_SP), cx.param_env()) {
+ if ty.is_unpin(tcx, cx.param_env()) {
PointerKind::UniqueBorrowed
} else {
PointerKind::UniqueBorrowedPinned
pub use self::Variance::*;
use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason};
use crate::metadata::ModChild;
-use crate::middle::privacy::AccessLevels;
+use crate::middle::privacy::EffectiveVisibilities;
use crate::mir::{Body, GeneratorLayout};
use crate::traits::{self, Reveal};
use crate::ty;
};
pub use self::context::{
tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
- CtxtInterners, DeducedParamAttrs, DelaySpanBugEmitted, FreeRegionInfo, GeneratorDiagnosticData,
+ CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GeneratorDiagnosticData,
GeneratorInteriorTypeCause, GlobalCtxt, Lift, OnDiskCache, TyCtxt, TypeckResults, UserType,
UserTypeAnnotationIndex,
};
pub expn_that_defined: FxHashMap<LocalDefId, ExpnId>,
/// Reference span for definitions.
pub source_span: IndexVec<LocalDefId, Span>,
- pub access_levels: AccessLevels,
+ pub effective_visibilities: EffectiveVisibilities,
pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
pub maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
pub maybe_unused_extern_crates: Vec<(LocalDefId, Span)>,
/// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err`
/// with the name of the crate containing the impl.
- pub fn span_of_impl(self, impl_did: DefId) -> Result<Span, Symbol> {
- if let Some(impl_did) = impl_did.as_local() {
- Ok(self.def_span(impl_did))
+ pub fn span_of_impl(self, impl_def_id: DefId) -> Result<Span, Symbol> {
+ if let Some(impl_def_id) = impl_def_id.as_local() {
+ Ok(self.def_span(impl_def_id))
} else {
- Err(self.crate_name(impl_did.krate))
+ Err(self.crate_name(impl_def_id.krate))
}
}
&& if self.features().collapse_debuginfo {
span.in_macro_expansion_with_collapse_debuginfo()
} else {
- span.from_expansion()
+ // Inlined spans should not be collapsed as that leads to all of the
+ // inlined code being attributed to the inline callsite.
+ span.from_expansion() && !span.is_inlined()
}
}
static NO_TRIMMED_PATH: Cell<bool> = const { Cell::new(false) };
static NO_QUERIES: Cell<bool> = const { Cell::new(false) };
static NO_VISIBLE_PATH: Cell<bool> = const { Cell::new(false) };
- static NO_VERBOSE_CONSTANTS: Cell<bool> = const { Cell::new(false) };
}
macro_rules! define_helper {
/// Prevent selection of visible paths. `Display` impl of DefId will prefer
/// visible (public) reexports of types as paths.
fn with_no_visible_paths(NoVisibleGuard, NO_VISIBLE_PATH);
- /// Prevent verbose printing of constants. Verbose printing of constants is
- /// never desirable in some contexts like `std::any::type_name`.
- fn with_no_verbose_constants(NoVerboseConstantsGuard, NO_VERBOSE_CONSTANTS);
);
/// The "region highlights" are used to control region printing during
}
ty::FnPtr(ref bare_fn) => p!(print(bare_fn)),
ty::Infer(infer_ty) => {
- let verbose = self.tcx().sess.verbose();
+ let verbose = self.should_print_verbose();
if let ty::TyVar(ty_vid) = infer_ty {
if let Some(name) = self.ty_infer_name(ty_vid) {
p!(write("{}", name))
p!(print_def_path(def_id, &[]));
}
ty::Projection(ref data) => {
- if !(self.tcx().sess.verbose() || NO_QUERIES.with(|q| q.get()))
+ if !(self.should_print_verbose() || NO_QUERIES.with(|q| q.get()))
&& self.tcx().def_kind(data.item_def_id) == DefKind::ImplTraitPlaceholder
{
return self.pretty_print_opaque_impl_type(data.item_def_id, data.substs);
// only affect certain debug messages (e.g. messages printed
// from `rustc_middle::ty` during the computation of `tcx.predicates_of`),
// and should have no effect on any compiler output.
- if self.tcx().sess.verbose() || NO_QUERIES.with(|q| q.get()) {
+ if self.should_print_verbose() || NO_QUERIES.with(|q| q.get()) {
p!(write("Opaque({:?}, {:?})", def_id, substs));
return Ok(self);
}
hir::Movability::Static => p!("static "),
}
- if !self.tcx().sess.verbose() {
+ if !self.should_print_verbose() {
p!("generator");
// FIXME(eddyb) should use `def_span`.
if let Some(did) = did.as_local() {
}
ty::Closure(did, substs) => {
p!(write("["));
- if !self.tcx().sess.verbose() {
+ if !self.should_print_verbose() {
p!(write("closure"));
// FIXME(eddyb) should use `def_span`.
if let Some(did) = did.as_local() {
}
ty::Array(ty, sz) => {
p!("[", print(ty), "; ");
- if !NO_VERBOSE_CONSTANTS.with(|flag| flag.get()) && self.tcx().sess.verbose() {
+ if self.should_print_verbose() {
p!(write("{:?}", sz));
} else if let ty::ConstKind::Unevaluated(..) = sz.kind() {
// Do not try to evaluate unevaluated constants. If we are const evaluating an
// Special-case `Fn(...) -> ...` and re-sugar it.
let fn_trait_kind = cx.tcx().fn_trait_kind_from_lang_item(principal.def_id);
- if !cx.tcx().sess.verbose() && fn_trait_kind.is_some() {
+ if !cx.should_print_verbose() && fn_trait_kind.is_some() {
if let ty::Tuple(tys) = principal.substs.type_at(0).kind() {
let mut projections = predicates.projection_bounds();
if let (Some(proj), None) = (projections.next(), projections.next()) {
//
// To avoid causing instabilities in compiletest
// output, sort the auto-traits alphabetically.
- auto_traits.sort_by_cached_key(|did| self.tcx().def_path_str(*did));
+ auto_traits.sort_by_cached_key(|did| with_no_trimmed_paths!(self.tcx().def_path_str(*did)));
for def_id in auto_traits {
if !first {
) -> Result<Self::Const, Self::Error> {
define_scoped_cx!(self);
- if !NO_VERBOSE_CONSTANTS.with(|flag| flag.get()) && self.tcx().sess.verbose() {
+ if self.should_print_verbose() {
p!(write("Const({:?}: {:?})", ct.kind(), ct.ty()));
return Ok(self);
}
) -> Result<Self::Const, Self::Error> {
define_scoped_cx!(self);
- if !NO_VERBOSE_CONSTANTS.with(|flag| flag.get()) && self.tcx().sess.verbose() {
+ if self.should_print_verbose() {
p!(write("ValTree({:?}: ", valtree), print(ty), ")");
return Ok(self);
}
Ok(cx)
})
}
+
+ fn should_print_verbose(&self) -> bool {
+ self.tcx().sess.verbose()
+ }
}
// HACK(eddyb) boxed to avoid moving around a large struct by-value.
}
}
- let verbose = self.tcx.sess.verbose();
+ let verbose = self.should_print_verbose();
disambiguated_data.fmt_maybe_verbose(&mut self, verbose)?;
self.empty_path = false;
return true;
}
- if self.tcx.sess.verbose() {
+ if self.should_print_verbose() {
return true;
}
return Ok(self);
}
- if self.tcx.sess.verbose() {
+ if self.should_print_verbose() {
p!(write("{:?}", region));
return Ok(self);
}
// If this is an anonymous placeholder, don't rename. Otherwise, in some
// async fns, we get a `for<'r> Send` bound
match kind {
- ty::BrAnon(_) | ty::BrEnv => r,
+ ty::BrAnon(..) | ty::BrEnv => r,
_ => {
// Index doesn't matter, since this is just for naming and these never get bound
let br = ty::BoundRegion { var: ty::BoundVar::from_u32(0), kind };
// aren't named. Eventually, we might just want this as the default, but
// this is not *quite* right and changes the ordering of some output
// anyways.
- let (new_value, map) = if self.tcx().sess.verbose() {
+ let (new_value, map) = if self.should_print_verbose() {
let regions: Vec<_> = value
.bound_vars()
.into_iter()
let ty::BoundVariableKind::Region(var) = var else {
// This doesn't really matter because it doesn't get used,
// it's just an empty value
- return ty::BrAnon(0);
+ return ty::BrAnon(0, None);
};
match var {
- ty::BrAnon(_) | ty::BrEnv => {
+ ty::BrAnon(..) | ty::BrEnv => {
start_or_continue(&mut self, "for<", ", ");
let name = next_name(&self);
debug!(?name);
binder_level_idx: ty::DebruijnIndex,
br: ty::BoundRegion| {
let (name, kind) = match br.kind {
- ty::BrAnon(_) | ty::BrEnv => {
+ ty::BrAnon(..) | ty::BrEnv => {
let name = next_name(&self);
if let Some(lt_idx) = lifetime_idx {
// Iterate all local crate items no matter where they are defined.
let hir = tcx.hir();
for id in hir.items() {
- if matches!(tcx.def_kind(id.def_id), DefKind::Use) {
+ if matches!(tcx.def_kind(id.owner_id), DefKind::Use) {
continue;
}
continue;
}
- let def_id = item.def_id.to_def_id();
+ let def_id = item.owner_id.to_def_id();
let ns = tcx.def_kind(def_id).ns().unwrap_or(Namespace::TypeNS);
collect_fn(&item.ident, ns, def_id);
}
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
use crate::middle::lib_features::LibFeatures;
-use crate::middle::privacy::AccessLevels;
+use crate::middle::privacy::EffectiveVisibilities;
use crate::middle::resolve_lifetime::{ObjectLifetimeDefault, Region, ResolveLifetimes};
use crate::middle::stability::{self, DeprecationEntry};
use crate::mir;
use rustc_data_structures::steal::Steal;
use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::unord::UnordSet;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
au.substs,
bu.substs,
)?;
- return Ok(tcx.mk_const(ty::ConstS {
- kind: ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def: au.def, substs }),
- ty: a.ty(),
- }));
+ return Ok(tcx.mk_const(
+ ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def: au.def, substs }),
+ a.ty(),
+ ));
}
_ => false,
};
impl fmt::Debug for ty::BoundRegionKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
- ty::BrAnon(n) => write!(f, "BrAnon({:?})", n),
+ ty::BrAnon(n, span) => write!(f, "BrAnon({n:?}, {span:?})"),
ty::BrNamed(did, name) => {
if did.is_crate_root() {
write!(f, "BrNamed({})", name)
Field,
interpret::Scalar,
rustc_target::abi::Size,
- ty::DelaySpanBugEmitted,
rustc_type_ir::DebruijnIndex,
ty::BoundVar,
ty::Placeholder<ty::BoundVar>,
let ty = self.ty().try_fold_with(folder)?;
let kind = self.kind().try_fold_with(folder)?;
if ty != self.ty() || kind != self.kind() {
- Ok(folder.tcx().mk_const(ty::ConstS { ty, kind }))
+ Ok(folder.tcx().mk_const(kind, ty))
} else {
Ok(self)
}
use rustc_index::vec::Idx;
use rustc_macros::HashStable;
use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::Span;
use rustc_target::abi::VariantIdx;
use rustc_target::spec::abi;
use std::borrow::Cow;
#[derive(HashStable)]
pub enum BoundRegionKind {
/// An anonymous region parameter for a given fn (&T)
- BrAnon(u32),
+ BrAnon(u32, Option<Span>),
/// Named region parameters for functions (a in &'a T)
///
pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
tcx.mk_ty_param(self.index, self.name)
}
+
+ pub fn span_from_generics(&self, tcx: TyCtxt<'tcx>, item_with_generics: DefId) -> Span {
+ let generics = tcx.generics_of(item_with_generics);
+ let type_param = generics.type_param(self, tcx);
+ tcx.def_span(type_param.def_id)
+ }
}
#[derive(Copy, Clone, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)]
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use crate::ty::layout::IntegerExt;
-use crate::ty::query::TyCtxtAt;
use crate::ty::{
self, DefIdTree, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
TypeVisitable,
/// does copies even when the type actually doesn't satisfy the
/// full requirements for the `Copy` trait (cc #29149) -- this
/// winds up being reported as an error during NLL borrow check.
- pub fn is_copy_modulo_regions(
- self,
- tcx_at: TyCtxtAt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- ) -> bool {
- self.is_trivially_pure_clone_copy() || tcx_at.is_copy_raw(param_env.and(self))
+ pub fn is_copy_modulo_regions(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+ self.is_trivially_pure_clone_copy() || tcx.is_copy_raw(param_env.and(self))
}
/// Checks whether values of this type `T` have a size known at
/// over-approximation in generic contexts, where one can have
/// strange rules like `<T as Foo<'static>>::Bar: Sized` that
/// actually carry lifetime requirements.
- pub fn is_sized(self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
- self.is_trivially_sized(tcx_at.tcx) || tcx_at.is_sized_raw(param_env.and(self))
+ pub fn is_sized(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+ self.is_trivially_sized(tcx) || tcx.is_sized_raw(param_env.and(self))
}
/// Checks whether values of this type `T` implement the `Freeze`
/// optimization as well as the rules around static values. Note
/// that the `Freeze` trait is not exposed to end users and is
/// effectively an implementation detail.
- pub fn is_freeze(self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
- self.is_trivially_freeze() || tcx_at.is_freeze_raw(param_env.and(self))
+ pub fn is_freeze(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+ self.is_trivially_freeze() || tcx.is_freeze_raw(param_env.and(self))
}
/// Fast path helper for testing if a type is `Freeze`.
}
/// Checks whether values of this type `T` implement the `Unpin` trait.
- pub fn is_unpin(self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
- self.is_trivially_unpin() || tcx_at.is_unpin_raw(param_env.and(self))
+ pub fn is_unpin(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
+ self.is_trivially_unpin() || tcx.is_unpin_raw(param_env.and(self))
}
/// Fast path helper for testing if a type is `Unpin`.
fn references_error(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_ERROR)
}
- fn error_reported(&self) -> Option<ErrorGuaranteed> {
+ fn error_reported(&self) -> Result<(), ErrorGuaranteed> {
if self.references_error() {
- Some(ErrorGuaranteed::unchecked_claim_error_was_emitted())
+ if let Some(reported) = ty::tls::with(|tcx| tcx.sess.has_errors()) {
+ Err(reported)
+ } else {
+ bug!("expect tcx.sess.has_errors return true");
+ }
} else {
- None
+ Ok(())
}
}
fn has_non_region_param(&self) -> bool {
Constant { user_ty, span, literal }
}
ExprKind::ConstParam { param, def_id: _ } => {
- let const_param =
- tcx.mk_const(ty::ConstS { kind: ty::ConstKind::Param(param), ty: expr.ty });
+ let const_param = tcx.mk_const(ty::ConstKind::Param(param), expr.ty);
let literal = ConstantKind::Ty(const_param);
Constant { user_ty: None, span, literal }
if tcx.features().unsized_fn_params {
let ty = expr.ty;
- let span = expr.span;
let param_env = this.param_env;
- if !ty.is_sized(tcx.at(span), param_env) {
+ if !ty.is_sized(tcx, param_env) {
// !sized means !copy, so this is an unsized move
- assert!(!ty.is_copy_modulo_regions(tcx.at(span), param_env));
+ assert!(!ty.is_copy_modulo_regions(tcx, param_env));
// As described above, detect the case where we are passing a value of unsized
// type, and that value is coming from the deref of a box.
use rustc_index::vec::Idx;
use rustc_middle::ty::util::IntTypeExt;
+use rustc_target::abi::{Abi, Primitive};
use crate::build::expr::as_place::PlaceBase;
use crate::build::expr::category::{Category, RvalueFunc};
let (source, ty) = if let ty::Adt(adt_def, ..) = source.ty.kind() && adt_def.is_enum() {
let discr_ty = adt_def.repr().discr_type().to_ty(this.tcx);
let temp = unpack!(block = this.as_temp(block, scope, source, Mutability::Not));
+ let layout = this.tcx.layout_of(this.param_env.and(source.ty));
let discr = this.temp(discr_ty, source.span);
this.cfg.push_assign(
block,
discr,
Rvalue::Discriminant(temp.into()),
);
+ let (op,ty) = (Operand::Move(discr), discr_ty);
+
+ if let Abi::Scalar(scalar) = layout.unwrap().abi{
+ if let Primitive::Int(_, signed) = scalar.primitive() {
+ let range = scalar.valid_range(&this.tcx);
+ // FIXME: Handle wraparound cases too.
+ if range.end >= range.start {
+ let mut assumer = |range: u128, bin_op: BinOp| {
+ // We will be overwriting this val if our scalar is signed value
+ // because sign extension on unsigned types might cause unintended things
+ let mut range_val =
+ ConstantKind::from_bits(this.tcx, range, ty::ParamEnv::empty().and(discr_ty));
+ let bool_ty = this.tcx.types.bool;
+ if signed {
+ let scalar_size_extend = scalar.size(&this.tcx).sign_extend(range);
+ let discr_layout = this.tcx.layout_of(this.param_env.and(discr_ty));
+ let truncated_val = discr_layout.unwrap().size.truncate(scalar_size_extend);
+ range_val = ConstantKind::from_bits(
+ this.tcx,
+ truncated_val,
+ ty::ParamEnv::empty().and(discr_ty),
+ );
+ }
+ let lit_op = this.literal_operand(expr.span, range_val);
+ let is_bin_op = this.temp(bool_ty, expr_span);
+ this.cfg.push_assign(
+ block,
+ source_info,
+ is_bin_op,
+ Rvalue::BinaryOp(bin_op, Box::new(((lit_op), (Operand::Copy(discr))))),
+ );
+ this.cfg.push(
+ block,
+ Statement {
+ source_info,
+ kind: StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume(
+ Operand::Copy(is_bin_op),
+ ))),
+ },
+ )
+ };
+ assumer(range.end, BinOp::Ge);
+ assumer(range.start, BinOp::Le);
+ }
+ }
+ }
+
+ (op,ty)
- (Operand::Move(discr), discr_ty)
} else {
let ty = source.ty;
let source = unpack!(
let arm_block = this.bind_pattern(
outer_source_info,
candidate,
- arm.guard.as_ref(),
&fake_borrow_temps,
scrutinee_span,
- Some(arm.span),
- Some(arm.scope),
- Some(match_scope),
+ Some((arm, match_scope)),
false,
);
&mut self,
outer_source_info: SourceInfo,
candidate: Candidate<'_, 'tcx>,
- guard: Option<&Guard<'tcx>>,
fake_borrow_temps: &[(Place<'tcx>, Local)],
scrutinee_span: Span,
- arm_span: Option<Span>,
- arm_scope: Option<region::Scope>,
- match_scope: Option<region::Scope>,
+ arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>,
storages_alive: bool,
) -> BasicBlock {
if candidate.subcandidates.is_empty() {
self.bind_and_guard_matched_candidate(
candidate,
&[],
- guard,
fake_borrow_temps,
scrutinee_span,
- arm_span,
- match_scope,
+ arm_match_scope,
true,
storages_alive,
)
// we lower the guard.
let target_block = self.cfg.start_new_block();
let mut schedule_drops = true;
+ let arm = arm_match_scope.unzip().0;
// We keep a stack of all of the bindings and type ascriptions
// from the parent candidates that we visit, that also need to
// be bound for each candidate.
candidate,
&mut Vec::new(),
&mut |leaf_candidate, parent_bindings| {
- if let Some(arm_scope) = arm_scope {
- self.clear_top_scope(arm_scope);
+ if let Some(arm) = arm {
+ self.clear_top_scope(arm.scope);
}
let binding_end = self.bind_and_guard_matched_candidate(
leaf_candidate,
parent_bindings,
- guard,
&fake_borrow_temps,
scrutinee_span,
- arm_span,
- match_scope,
+ arm_match_scope,
schedule_drops,
storages_alive,
);
- if arm_scope.is_none() {
+ if arm.is_none() {
schedule_drops = false;
}
self.cfg.goto(binding_end, outer_source_info, target_block);
self.bind_pattern(
self.source_info(irrefutable_pat.span),
candidate,
- None,
&fake_borrow_temps,
irrefutable_pat.span,
None,
- None,
- None,
false,
)
.unit()
let post_guard_block = self.bind_pattern(
self.source_info(pat.span),
guard_candidate,
- None,
&fake_borrow_temps,
expr.span,
None,
- None,
- None,
false,
);
&mut self,
candidate: Candidate<'pat, 'tcx>,
parent_bindings: &[(Vec<Binding<'tcx>>, Vec<Ascription<'tcx>>)],
- guard: Option<&Guard<'tcx>>,
fake_borrows: &[(Place<'tcx>, Local)],
scrutinee_span: Span,
- arm_span: Option<Span>,
- match_scope: Option<region::Scope>,
+ arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>,
schedule_drops: bool,
storages_alive: bool,
) -> BasicBlock {
// the reference that we create for the arm.
// * So we eagerly create the reference for the arm and then take a
// reference to that.
- if let Some(guard) = guard {
+ if let Some((arm, match_scope)) = arm_match_scope
+ && let Some(guard) = &arm.guard
+ {
let tcx = self.tcx;
let bindings = parent_bindings
.iter()
self.cfg.push_assign(block, scrutinee_source_info, Place::from(temp), borrow);
}
- let arm_span = arm_span.unwrap();
- let match_scope = match_scope.unwrap();
let mut guard_span = rustc_span::DUMMY_SP;
let (post_guard_block, otherwise_post_guard_block) =
e,
None,
match_scope,
- this.source_info(arm_span),
+ this.source_info(arm.span),
)
}
Guard::IfLet(ref pat, scrutinee) => {
let s = &this.thir[scrutinee];
guard_span = s.span;
- this.lower_let_expr(block, s, pat, match_scope, None, arm_span)
+ this.lower_let_expr(block, s, pat, match_scope, None, arm.span)
}
});
let matching = this.bind_pattern(
this.source_info(pattern.span),
candidate,
- None,
&fake_borrow_temps,
initializer_span,
None,
- None,
- None,
true,
);
// This block is for the failure case
let failure = this.bind_pattern(
this.source_info(else_block_span),
wildcard,
- None,
&fake_borrow_temps,
initializer_span,
None,
- None,
- None,
true,
);
this.break_for_else(failure, *let_else_scope, this.source_info(initializer_span));
};
match borrow_kind {
BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique => {
- if !ty.is_freeze(self.tcx.at(pat.span), self.param_env) {
+ if !ty.is_freeze(self.tcx, self.param_env) {
self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField);
}
}
if visitor.found {
match borrow_kind {
BorrowKind::Shallow | BorrowKind::Shared | BorrowKind::Unique
- if !self.thir[arg]
- .ty
- .is_freeze(self.tcx.at(self.thir[arg].span), self.param_env) =>
+ if !self.thir[arg].ty.is_freeze(self.tcx, self.param_env) =>
{
self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField)
}
intravisit::walk_local(self, loc);
let els = loc.els;
if let Some(init) = loc.init && els.is_some() {
- self.check_let(&loc.pat, init, loc.span);
+ // Build a span without the else { ... } as we don't want to underline
+ // the entire else block in the IDE setting.
+ let span = loc.span.with_hi(init.span.hi());
+ self.check_let(&loc.pat, init, span);
}
let (msg, sp) = match loc.source {
_ => "aren't",
},
),
- " else { todo!() }".to_string(),
+ " else { todo!() }",
Applicability::HasPlaceholders,
);
}
count: usize,
span: Span,
) {
- let span = match source {
- LetSource::LetElse(span) => span,
- _ => span,
- };
-
macro_rules! emit_diag {
(
$lint:expr,
"removing the guard and adding a `let` inside the match arm"
);
}
- LetSource::LetElse(..) => {
+ LetSource::LetElse => {
emit_diag!(
lint,
"`let...else`",
}
/// Check if a by-value binding is by-value. That is, check if the binding's type is not `Copy`.
-fn is_binding_by_move(cx: &MatchVisitor<'_, '_, '_>, hir_id: HirId, span: Span) -> bool {
- !cx.typeck_results.node_type(hir_id).is_copy_modulo_regions(cx.tcx.at(span), cx.param_env)
+fn is_binding_by_move(cx: &MatchVisitor<'_, '_, '_>, hir_id: HirId) -> bool {
+ !cx.typeck_results.node_type(hir_id).is_copy_modulo_regions(cx.tcx, cx.param_env)
}
/// Check that there are no borrow or move conflicts in `binding @ subpat` patterns.
// Get the binding move, extract the mutability if by-ref.
let mut_outer = match typeck_results.extract_binding_mode(sess, pat.hir_id, pat.span) {
- Some(ty::BindByValue(_)) if is_binding_by_move(cx, pat.hir_id, pat.span) => {
+ Some(ty::BindByValue(_)) if is_binding_by_move(cx, pat.hir_id) => {
// We have `x @ pat` where `x` is by-move. Reject all borrows in `pat`.
let mut conflicts_ref = Vec::new();
sub.each_binding(|_, hir_id, span, _| {
(Mutability::Mut, Mutability::Mut) => conflicts_mut_mut.push((span, name)), // 2x `ref mut`.
_ => conflicts_mut_ref.push((span, name)), // `ref` + `ref mut` in either direction.
},
- Some(ty::BindByValue(_)) if is_binding_by_move(cx, hir_id, span) => {
+ Some(ty::BindByValue(_)) if is_binding_by_move(cx, hir_id) => {
conflicts_move.push((span, name)) // `ref mut?` + by-move conflict.
}
Some(ty::BindByValue(_)) | None => {} // `ref mut?` + by-copy is fine.
GenericLet,
IfLet,
IfLetGuard,
- LetElse(Span),
+ LetElse,
WhileLet,
}
let parent_parent = hir.get_parent_node(parent);
let parent_parent_node = hir.get(parent_parent);
match parent_parent_node {
- hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_), span, .. }) => {
- return LetSource::LetElse(*span);
+ hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(_), .. }) => {
+ return LetSource::LetElse;
}
hir::Node::Arm(hir::Arm { guard: Some(hir::Guard::If(_)), .. }) => {
return LetSource::IfLetGuard;
// convert the dereferenced constant to a pattern that is the sub-pattern of the
// deref pattern.
_ => {
- if !pointee_ty.is_sized(tcx.at(span), param_env) {
+ if !pointee_ty.is_sized(tcx, param_env) {
// `tcx.deref_mir_constant()` below will ICE with an unsized type
// (except slices, which are handled in a separate arm above).
let msg = format!("cannot use unsized non-slice type `{}` in constant patterns", pointee_ty);
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::FnDef(..) => {
PatKind::Constant { value: cv }
}
- ty::RawPtr(pointee) if pointee.ty.is_sized(tcx.at(span), param_env) => {
+ ty::RawPtr(pointee) if pointee.ty.is_sized(tcx, param_env) => {
PatKind::Constant { value: cv }
}
// FIXME: these can have very surprising behaviour where optimization levels or other
self.drop_ladder(fields, succ, unwind).0
}
+ #[instrument(level = "debug", ret)]
fn open_drop_for_box(&mut self, adt: ty::AdtDef<'tcx>, substs: SubstsRef<'tcx>) -> BasicBlock {
- debug!("open_drop_for_box({:?}, {:?}, {:?})", self, adt, substs);
-
// drop glue is sent straight to codegen
// box cannot be directly dereferenced
let unique_ty = adt.non_enum_variant().fields[0].ty(self.tcx(), substs);
self.drop_subpath(interior, interior_path, succ, unwind_succ)
}
+ #[instrument(level = "debug", ret)]
fn open_drop_for_adt(&mut self, adt: ty::AdtDef<'tcx>, substs: SubstsRef<'tcx>) -> BasicBlock {
- debug!("open_drop_for_adt({:?}, {:?}, {:?})", self, adt, substs);
if adt.variants().is_empty() {
return self.elaborator.patch().new_block(BasicBlockData {
statements: vec![],
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::hir_id::HirId;
use rustc_hir::intravisit;
+use rustc_hir::{BlockCheckMode, ExprKind, Node};
use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::ty::query::Providers;
| StatementKind::Retag { .. }
| StatementKind::AscribeUserType(..)
| StatementKind::Coverage(..)
+ | StatementKind::Intrinsic(..)
| StatementKind::Nop => {
// safe (at least as emitted during MIR construction)
}
-
- // Move to above list once mir construction uses it.
- StatementKind::Intrinsic(..) => unreachable!(),
}
self.super_statement(statement, location);
}
} else if !place
.ty(self.body, self.tcx)
.ty
- .is_freeze(self.tcx.at(self.source_info.span), self.param_env)
+ .is_freeze(self.tcx, self.param_env)
{
UnsafetyViolationDetails::BorrowOfLayoutConstrainedField
} else {
for &UnsafetyViolation { source_info, lint_root, kind, details } in violations.iter() {
let (description, note) = details.description_and_note();
- // Report an error.
- let unsafe_fn_msg =
- if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) { " function or" } else { "" };
-
match kind {
UnsafetyViolationKind::General => {
// once
- struct_span_err!(
+ let unsafe_fn_msg = if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) {
+ " function or"
+ } else {
+ ""
+ };
+
+ let mut err = struct_span_err!(
tcx.sess,
source_info.span,
E0133,
"{} is unsafe and requires unsafe{} block",
description,
unsafe_fn_msg,
- )
- .span_label(source_info.span, description)
- .note(note)
- .emit();
+ );
+ err.span_label(source_info.span, description).note(note);
+ let note_non_inherited = tcx.hir().parent_iter(lint_root).find(|(id, node)| {
+ if let Node::Expr(block) = node
+ && let ExprKind::Block(block, _) = block.kind
+ && let BlockCheckMode::UnsafeBlock(_) = block.rules
+ {
+ true
+ }
+ else if let Some(sig) = tcx.hir().fn_sig_by_hir_id(*id)
+ && sig.header.is_unsafe()
+ {
+ true
+ } else {
+ false
+ }
+ });
+ if let Some((id, _)) = note_non_inherited {
+ let span = tcx.hir().span(id);
+ err.span_label(
+ tcx.sess.source_map().guess_head_span(span),
+ "items do not inherit unsafety from separate enclosing items",
+ );
+ }
+
+ err.emit();
}
UnsafetyViolationKind::UnsafeFn => tcx.struct_span_lint_hir(
UNSAFE_OP_IN_UNSAFE_FN,
}
if !rvalue
.ty(&self.ecx.frame().body.local_decls, *self.ecx.tcx)
- .is_sized(self.ecx.tcx, self.param_env)
+ .is_sized(*self.ecx.tcx, self.param_env)
{
// the interpreter doesn't support unsized locals (only unsized arguments),
// but rustc does (in a kinda broken way), so we have to skip them here
}
if !rvalue
.ty(&self.ecx.frame().body.local_decls, *self.ecx.tcx)
- .is_sized(self.ecx.tcx, self.param_env)
+ .is_sized(*self.ecx.tcx, self.param_env)
{
// the interpreter doesn't support unsized locals (only unsized arguments),
// but rustc does (in a kinda broken way), so we have to skip them here
use rustc_middle::mir::{Body, Local, Location, Operand, Terminator, TerminatorKind, RETURN_PLACE};
use rustc_middle::ty::{self, DeducedParamAttrs, ParamEnv, Ty, TyCtxt};
use rustc_session::config::OptLevel;
-use rustc_span::DUMMY_SP;
/// A visitor that determines which arguments have been mutated. We can't use the mutability field
/// on LocalDecl for this because it has no meaning post-optimization.
body.local_decls.iter().skip(1).take(body.arg_count).enumerate().map(
|(arg_index, local_decl)| DeducedParamAttrs {
read_only: !deduce_read_only.mutable_args.contains(arg_index)
- && local_decl.ty.is_freeze(tcx.at(DUMMY_SP), ParamEnv::reveal_all()),
+ && local_decl.ty.is_freeze(tcx, ParamEnv::reveal_all()),
},
),
);
let mut body = tcx.mir_built(def).steal();
- rustc_middle::mir::dump_mir(tcx, None, "mir_map", &0, &body, |_, _| Ok(()));
+ pass_manager::dump_mir_for_phase_change(tcx, &body);
pm::run_passes(
tcx,
let param_env = tcx.param_env(def_id);
let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty);
- let is_copy = self_ty.is_copy_modulo_regions(tcx.at(builder.span), param_env);
+ let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env);
let dest = Place::return_place();
let src = tcx.mk_place_deref(Place::from(Local::new(1 + 0)));
/// Builds a "call" shim for `instance`. The shim calls the function specified by `call_kind`,
/// first adjusting its first argument according to `rcvr_adjustment`.
+#[instrument(level = "debug", skip(tcx), ret)]
fn build_call_shim<'tcx>(
tcx: TyCtxt<'tcx>,
instance: ty::InstanceDef<'tcx>,
rcvr_adjustment: Option<Adjustment>,
call_kind: CallKind<'tcx>,
) -> Body<'tcx> {
- debug!(
- "build_call_shim(instance={:?}, rcvr_adjustment={:?}, call_kind={:?})",
- instance, rcvr_adjustment, call_kind
- );
-
// `FnPtrShim` contains the fn pointer type that a call shim is being built for - this is used
// to substitute into the signature of the shim. It is not necessary for users of this
// MIR body to perform further substitutions (see `InstanceDef::has_polymorphic_mir_body`).
let span = tcx.def_span(def_id);
- debug!("build_call_shim: sig={:?}", sig);
+ debug!(?sig);
let mut local_decls = local_decls_for_sig(&sig, span);
let source_info = SourceInfo::outermost(span);
span,
);
- rustc_middle::mir::dump_mir(tcx, None, "mir_map", &0, &body, |_, _| Ok(()));
+ crate::pass_manager::dump_mir_for_phase_change(tcx, &body);
body
}
use std::ops::Range;
use std::path::PathBuf;
-use crate::errors::{LargeAssignmentsLint, RecursionLimit, RequiresLangItem, TypeLengthLimit};
+use crate::errors::{LargeAssignmentsLint, RecursionLimit, TypeLengthLimit};
#[derive(PartialEq)]
pub enum MonoItemCollectionMode {
let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| {
let param_env = ty::ParamEnv::reveal_all();
let type_has_metadata = |ty: Ty<'tcx>| -> bool {
- if ty.is_sized(tcx.at(DUMMY_SP), param_env) {
+ if ty.is_sized(tcx, param_env) {
return false;
}
let tail = tcx.struct_tail_erasing_lifetimes(ty, param_env);
impl<'v> RootCollector<'_, 'v> {
fn process_item(&mut self, id: hir::ItemId) {
- match self.tcx.def_kind(id.def_id) {
+ match self.tcx.def_kind(id.owner_id) {
DefKind::Enum | DefKind::Struct | DefKind::Union => {
let item = self.tcx.hir().item(id);
match item.kind {
if self.mode == MonoItemCollectionMode::Eager {
debug!(
"RootCollector: ADT drop-glue for {}",
- self.tcx.def_path_str(item.def_id.to_def_id())
+ self.tcx.def_path_str(item.owner_id.to_def_id())
);
- let ty =
- Instance::new(item.def_id.to_def_id(), InternalSubsts::empty())
- .ty(self.tcx, ty::ParamEnv::reveal_all());
+ let ty = Instance::new(
+ item.owner_id.to_def_id(),
+ InternalSubsts::empty(),
+ )
+ .ty(self.tcx, ty::ParamEnv::reveal_all());
visit_drop_use(self.tcx, ty, true, DUMMY_SP, self.output);
}
}
DefKind::GlobalAsm => {
debug!(
"RootCollector: ItemKind::GlobalAsm({})",
- self.tcx.def_path_str(id.def_id.to_def_id())
+ self.tcx.def_path_str(id.owner_id.to_def_id())
);
self.output.push(dummy_spanned(MonoItem::GlobalAsm(id)));
}
DefKind::Static(..) => {
debug!(
"RootCollector: ItemKind::Static({})",
- self.tcx.def_path_str(id.def_id.to_def_id())
+ self.tcx.def_path_str(id.owner_id.to_def_id())
);
- self.output.push(dummy_spanned(MonoItem::Static(id.def_id.to_def_id())));
+ self.output.push(dummy_spanned(MonoItem::Static(id.owner_id.to_def_id())));
}
DefKind::Const => {
// const items only generate mono items if they are
// actually used somewhere. Just declaring them is insufficient.
// but even just declaring them must collect the items they refer to
- if let Ok(val) = self.tcx.const_eval_poly(id.def_id.to_def_id()) {
+ if let Ok(val) = self.tcx.const_eval_poly(id.owner_id.to_def_id()) {
collect_const_value(self.tcx, val, &mut self.output);
}
}
}
}
DefKind::Fn => {
- self.push_if_root(id.def_id.def_id);
+ self.push_if_root(id.owner_id.def_id);
}
_ => {}
}
}
fn process_impl_item(&mut self, id: hir::ImplItemId) {
- if matches!(self.tcx.def_kind(id.def_id), DefKind::AssocFn) {
- self.push_if_root(id.def_id.def_id);
+ if matches!(self.tcx.def_kind(id.owner_id), DefKind::AssocFn) {
+ self.push_if_root(id.owner_id.def_id);
}
}
return;
};
- let start_def_id = match self.tcx.lang_items().require(LangItem::Start) {
- Ok(s) => s,
- Err(lang_item_err) => {
- self.tcx
- .sess
- .emit_fatal(RequiresLangItem { lang_item: lang_item_err.0.name().to_string() });
- }
- };
+ let start_def_id = self.tcx.require_lang_item(LangItem::Start, None);
let main_ret_ty = self.tcx.fn_sig(main_def_id).output();
// Given that `main()` has no arguments,
) {
match item.kind {
hir::ItemKind::Impl(ref impl_) => {
+ if matches!(impl_.polarity, hir::ImplPolarity::Negative(_)) {
+ return;
+ }
+
for param in impl_.generics.params {
match param.kind {
hir::GenericParamKind::Lifetime { .. } => {}
debug!(
"create_mono_items_for_default_impls(item={})",
- tcx.def_path_str(item.def_id.to_def_id())
+ tcx.def_path_str(item.owner_id.to_def_id())
);
- if let Some(trait_ref) = tcx.impl_trait_ref(item.def_id) {
+ if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) {
let param_env = ty::ParamEnv::reveal_all();
let trait_ref = tcx.normalize_erasing_regions(param_env, trait_ref);
- let overridden_methods = tcx.impl_item_implementor_ids(item.def_id);
+ let overridden_methods = tcx.impl_item_implementor_ids(item.owner_id);
for method in tcx.provided_trait_methods(trait_ref.def_id) {
if overridden_methods.contains_key(&method.def_id) {
continue;
pub type_length: usize,
}
-#[derive(Diagnostic)]
-#[diag(monomorphize_requires_lang_item)]
-pub struct RequiresLangItem {
- pub lang_item: String,
-}
-
pub struct UnusedGenericParams {
pub span: Span,
pub param_spans: Vec<Span>,
}
impl IntoDiagnostic<'_> for UnusedGenericParams {
+ #[track_caller]
fn into_diagnostic(
self,
handler: &'_ rustc_errors::Handler,
Some(def_id)
}
MonoItem::Static(def_id) => Some(def_id),
- MonoItem::GlobalAsm(item_id) => Some(item_id.def_id.to_def_id()),
+ MonoItem::GlobalAsm(item_id) => Some(item_id.owner_id.to_def_id()),
}
}
};
}
MonoItem::GlobalAsm(item_id) => {
- return if tcx.is_reachable_non_generic(item_id.def_id) {
+ return if tcx.is_reachable_non_generic(item_id.owner_id) {
*can_be_internalized = false;
- default_visibility(tcx, item_id.def_id.to_def_id(), false)
+ default_visibility(tcx, item_id.owner_id.to_def_id(), false)
} else {
Visibility::Hidden
};
#[diag(parser_incorrect_semicolon)]
pub(crate) struct IncorrectSemicolon<'a> {
#[primary_span]
- #[suggestion_short(code = "", applicability = "machine-applicable")]
+ #[suggestion(style = "short", code = "", applicability = "machine-applicable")]
pub span: Span,
#[help]
pub opt_help: Option<()>,
#[derive(Subdiagnostic)]
pub(crate) enum InvalidComparisonOperatorSub {
- #[suggestion_short(use_instead, applicability = "machine-applicable", code = "{correct}")]
+ #[suggestion(
+ use_instead,
+ style = "short",
+ applicability = "machine-applicable",
+ code = "{correct}"
+ )]
Correctable {
#[primary_span]
span: Span,
#[derive(Subdiagnostic)]
pub(crate) enum InvalidLogicalOperatorSub {
- #[suggestion_short(
+ #[suggestion(
use_amp_amp_for_conjunction,
+ style = "short",
applicability = "machine-applicable",
code = "&&"
)]
Conjunction(#[primary_span] Span),
- #[suggestion_short(
+ #[suggestion(
use_pipe_pipe_for_disjunction,
+ style = "short",
applicability = "machine-applicable",
code = "||"
)]
#[diag(parser_tilde_is_not_unary_operator)]
pub(crate) struct TildeAsUnaryOperator(
#[primary_span]
- #[suggestion_short(applicability = "machine-applicable", code = "!")]
+ #[suggestion(style = "short", applicability = "machine-applicable", code = "!")]
pub Span,
);
#[derive(Subdiagnostic)]
pub enum NotAsNegationOperatorSub {
- #[suggestion_short(
+ #[suggestion(
parser_unexpected_token_after_not_default,
+ style = "short",
applicability = "machine-applicable",
code = "!"
)]
SuggestNotDefault(#[primary_span] Span),
- #[suggestion_short(
+ #[suggestion(
parser_unexpected_token_after_not_bitwise,
+ style = "short",
applicability = "machine-applicable",
code = "!"
)]
SuggestNotBitwise(#[primary_span] Span),
- #[suggestion_short(
+ #[suggestion(
parser_unexpected_token_after_not_logical,
+ style = "short",
applicability = "machine-applicable",
code = "!"
)]
#[primary_span]
#[label(parser_unexpected_token_after_label)]
pub span: Span,
- #[suggestion_verbose(suggestion_remove_label, code = "")]
+ #[suggestion(suggestion_remove_label, style = "verbose", code = "")]
pub remove_label: Option<Span>,
#[subdiagnostic]
pub enclose_in_block: Option<UnexpectedTokenAfterLabelSugg>,
pub span: Span,
#[label]
pub label: Span,
- #[suggestion_short(applicability = "machine-applicable", code = ": ")]
+ #[suggestion(style = "short", applicability = "machine-applicable", code = ": ")]
pub label_end: Span,
}
pub(crate) struct MissingSemicolonBeforeArray {
#[primary_span]
pub open_delim: Span,
- #[suggestion_verbose(applicability = "maybe-incorrect", code = ";")]
+ #[suggestion(style = "verbose", applicability = "maybe-incorrect", code = ";")]
pub semicolon: Span,
}
+#[derive(Diagnostic)]
+#[diag(parser_expect_dotdot_not_dotdotdot)]
+pub(crate) struct MissingDotDot {
+ #[primary_span]
+ pub token_span: Span,
+ #[suggestion(applicability = "maybe-incorrect", code = "..", style = "verbose")]
+ pub sugg_span: Span,
+}
+
#[derive(Diagnostic)]
#[diag(parser_invalid_block_macro_segment)]
pub(crate) struct InvalidBlockMacroSegment {
#[derive(Subdiagnostic)]
pub(crate) enum MissingInInForLoopSub {
// Has been misleading, at least in the past (closed Issue #48492), thus maybe-incorrect
- #[suggestion_short(use_in_not_of, applicability = "maybe-incorrect", code = "in")]
+ #[suggestion(use_in_not_of, style = "short", applicability = "maybe-incorrect", code = "in")]
InNotOf(#[primary_span] Span),
- #[suggestion_short(add_in, applicability = "maybe-incorrect", code = " in ")]
+ #[suggestion(add_in, style = "short", applicability = "maybe-incorrect", code = " in ")]
AddIn(#[primary_span] Span),
}
pub(crate) struct CommaAfterBaseStruct {
#[primary_span]
pub span: Span,
- #[suggestion_short(applicability = "machine-applicable", code = "")]
+ #[suggestion(style = "short", applicability = "machine-applicable", code = "")]
pub comma: Span,
}
#[diag(parser_use_eq_instead)]
pub(crate) struct UseEqInstead {
#[primary_span]
- #[suggestion_short(applicability = "machine-applicable", code = "=")]
+ #[suggestion(style = "short", applicability = "machine-applicable", code = "=")]
pub span: Span,
}
#[diag(parser_use_empty_block_not_semi)]
pub(crate) struct UseEmptyBlockNotSemi {
#[primary_span]
- #[suggestion_hidden(applicability = "machine-applicable", code = "{{}}")]
+ #[suggestion(style = "hidden", applicability = "machine-applicable", code = "{{}}")]
pub span: Span,
}
#[primary_span]
#[label]
pub span: Span,
- #[suggestion_verbose(suggestion_remove_plus, code = "", applicability = "machine-applicable")]
+ #[suggestion(
+ suggestion_remove_plus,
+ style = "verbose",
+ code = "",
+ applicability = "machine-applicable"
+ )]
pub remove_plus: Option<Span>,
#[subdiagnostic]
pub add_parentheses: Option<ExprParenthesesNeeded>,
#[help]
pub(crate) struct CompoundAssignmentExpressionInLet {
#[primary_span]
- #[suggestion_short(code = "=", applicability = "maybe-incorrect")]
+ #[suggestion(style = "short", code = "=", applicability = "maybe-incorrect")]
pub span: Span,
}
}
#[derive(Subdiagnostic)]
-#[suggestion_verbose(
+#[suggestion(
parser_sugg_escape_to_use_as_identifier,
+ style = "verbose",
applicability = "maybe-incorrect",
code = "r#"
)]
}
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedIdentifier {
+ #[track_caller]
fn into_diagnostic(
self,
handler: &'a rustc_errors::Handler,
}
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for ExpectedSemi {
+ #[track_caller]
fn into_diagnostic(
self,
handler: &'a rustc_errors::Handler,
applicability = "machine-applicable"
)]
ChangeToSemi(#[primary_span] Span),
- #[suggestion_short(parser_sugg_add_semi, code = ";", applicability = "machine-applicable")]
+ #[suggestion(
+ parser_sugg_add_semi,
+ style = "short",
+ code = ";",
+ applicability = "machine-applicable"
+ )]
AddSemi(#[primary_span] Span),
}
pub(crate) struct ComparisonOperatorsCannotBeChained {
#[primary_span]
pub span: Vec<Span>,
- #[suggestion_verbose(
+ #[suggestion(
parser_sugg_turbofish_syntax,
+ style = "verbose",
code = "::",
applicability = "maybe-incorrect"
)]
#[derive(Subdiagnostic)]
pub(crate) enum ComparisonOperatorsCannotBeChainedSugg {
- #[suggestion_verbose(
+ #[suggestion(
sugg_split_comparison,
+ style = "verbose",
code = " && {middle_term}",
applicability = "maybe-incorrect"
)]
pub(crate) struct UnexpectedConstInGenericParam {
#[primary_span]
pub span: Span,
- #[suggestion_verbose(code = "", applicability = "maybe-incorrect")]
+ #[suggestion(style = "verbose", code = "", applicability = "maybe-incorrect")]
pub to_remove: Option<Span>,
}
#[diag(parser_async_move_order_incorrect)]
pub(crate) struct AsyncMoveOrderIncorrect {
#[primary_span]
- #[suggestion_verbose(code = "async move", applicability = "maybe-incorrect")]
+ #[suggestion(style = "verbose", code = "async move", applicability = "maybe-incorrect")]
pub span: Span,
}
if string == "_" {
self.sess
.span_diagnostic
- .struct_span_warn(
+ .struct_span_err(
self.mk_sp(suffix_start, self.pos),
"underscore literal suffix is not allowed",
)
- .warn(
- "this was previously accepted by the compiler but is \
- being phased out; it will become a hard error in \
- a future release!",
- )
- .note(
- "see issue #42326 \
- <https://github.com/rust-lang/rust/issues/42326> \
- for more information",
- )
.emit();
None
} else {
segment: &PathSegment,
end: &[&TokenKind],
) -> bool {
+ if !self.may_recover() {
+ return false;
+ }
+
// This function is intended to be invoked after parsing a path segment where there are two
// cases:
//
/// Check if a method call with an intended turbofish has been written without surrounding
/// angle brackets.
pub(super) fn check_turbofish_missing_angle_brackets(&mut self, segment: &mut PathSegment) {
+ if !self.may_recover() {
+ return;
+ }
+
if token::ModSep == self.token.kind && segment.args.is_none() {
let snapshot = self.create_snapshot_for_diagnostic();
self.bump();
&mut self,
base: P<T>,
) -> PResult<'a, P<T>> {
+ if !self.may_recover() {
+ return Ok(base);
+ }
+
// Do not add `::` to expected tokens.
if self.token == token::ModSep {
if let Some(ty) = base.to_ty() {
}
pub(crate) fn maybe_recover_unexpected_block_label(&mut self) -> bool {
- let Some(label) = self.eat_label().filter(|_| {
- self.eat(&token::Colon) && self.token.kind == token::OpenDelim(Delimiter::Brace)
- }) else {
+ // Check for `'a : {`
+ if !(self.check_lifetime()
+ && self.look_ahead(1, |tok| tok.kind == token::Colon)
+ && self.look_ahead(2, |tok| tok.kind == token::OpenDelim(Delimiter::Brace)))
+ {
return false;
- };
+ }
+ let label = self.eat_label().expect("just checked if a label exists");
+ self.bump(); // eat `:`
let span = label.ident.span.to(self.prev_token.span);
let mut err = self.struct_span_err(span, "block label not supported here");
err.span_label(span, "not supported here");
InvalidNumLiteralSuffix, LabeledLoopInBreak, LeadingPlusNotSupported, LeftArrowOperator,
LifetimeInBorrowExpression, MacroInvocationWithQualifiedPath, MalformedLoopLabel,
MatchArmBodyWithoutBraces, MatchArmBodyWithoutBracesSugg, MissingCommaAfterMatchArm,
- MissingInInForLoop, MissingInInForLoopSub, MissingSemicolonBeforeArray, NoFieldsForFnCall,
- NotAsNegationOperator, NotAsNegationOperatorSub, OctalFloatLiteralNotSupported,
- OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields,
+ MissingDotDot, MissingInInForLoop, MissingInInForLoopSub, MissingSemicolonBeforeArray,
+ NoFieldsForFnCall, NotAsNegationOperator, NotAsNegationOperatorSub,
+ OctalFloatLiteralNotSupported, OuterAttributeNotAllowedOnIfElse, ParenthesesWithStructFields,
RequireColonAfterLabeledExpression, ShiftInterpretedAsGeneric, StructLiteralNotAllowedHere,
StructLiteralNotAllowedHereSugg, TildeAsUnaryOperator, UnexpectedTokenAfterLabel,
UnexpectedTokenAfterLabelSugg, WrapExpressionInParentheses,
Ok(expr) => Ok(expr),
Err(mut err) => match self.token.ident() {
Some((Ident { name: kw::Underscore, .. }, false))
- if self.look_ahead(1, |t| t == &token::Comma) =>
+ if self.may_recover() && self.look_ahead(1, |t| t == &token::Comma) =>
{
// Special-case handling of `foo(_, _, _)`
err.emit();
return None;
}
(Some(op), _) => (op, self.token.span),
- (None, Some((Ident { name: sym::and, span }, false))) => {
+ (None, Some((Ident { name: sym::and, span }, false))) if self.may_recover() => {
self.sess.emit_err(InvalidLogicalOperator {
span: self.token.span,
incorrect: "and".into(),
});
(AssocOp::LAnd, span)
}
- (None, Some((Ident { name: sym::or, span }, false))) => {
+ (None, Some((Ident { name: sym::or, span }, false))) if self.may_recover() => {
self.sess.emit_err(InvalidLogicalOperator {
span: self.token.span,
incorrect: "or".into(),
token::Ident(..) if this.token.is_keyword(kw::Box) => {
make_it!(this, attrs, |this, _| this.parse_box_expr(lo))
}
- token::Ident(..) if this.is_mistaken_not_ident_negation() => {
+ token::Ident(..) if this.may_recover() && this.is_mistaken_not_ident_negation() => {
make_it!(this, attrs, |this, _| this.recover_not_expr(lo))
}
_ => return this.parse_dot_or_call_expr(Some(attrs)),
let cast_expr = match self.parse_as_cast_ty() {
Ok(rhs) => mk_expr(self, lhs, rhs),
Err(type_err) => {
+ if !self.may_recover() {
+ return Err(type_err);
+ }
+
// Rewind to before attempting to parse the type with generics, to recover
// from situations like `x as usize < y` in which we first tried to parse
// `usize < y` as a type with generic arguments.
("cast", None)
};
- // Save the memory location of expr before parsing any following postfix operators.
- // This will be compared with the memory location of the output expression.
- // If they different we can assume we parsed another expression because the existing expression is not reallocated.
- let addr_before = &*cast_expr as *const _ as usize;
let with_postfix = self.parse_dot_or_call_expr_with_(cast_expr, span)?;
- let changed = addr_before != &*with_postfix as *const _ as usize;
// Check if an illegal postfix operator has been added after the cast.
- // If the resulting expression is not a cast, or has a different memory location, it is an illegal postfix operator.
- if !matches!(with_postfix.kind, ExprKind::Cast(_, _) | ExprKind::Type(_, _)) || changed {
+ // If the resulting expression is not a cast, it is an illegal postfix operator.
+ if !matches!(with_postfix.kind, ExprKind::Cast(_, _) | ExprKind::Type(_, _)) {
let msg = format!(
"{cast_kind} cannot be followed by {}",
match with_postfix.kind {
seq: &mut PResult<'a, P<Expr>>,
snapshot: Option<(SnapshotParser<'a>, ExprKind)>,
) -> Option<P<Expr>> {
+ if !self.may_recover() {
+ return None;
+ }
+
match (seq.as_mut(), snapshot) {
(Err(err), Some((mut snapshot, ExprKind::Path(None, path)))) => {
snapshot.bump(); // `(`
)
} else if self.check_inline_const(0) {
self.parse_const_block(lo.to(self.token.span), false)
- } else if self.is_do_catch_block() {
+ } else if self.may_recover() && self.is_do_catch_block() {
self.recover_do_catch()
} else if self.is_try_block() {
self.expect_keyword(kw::Try)?;
{
self.parse_block_expr(label, lo, BlockCheckMode::Default)
} else if !ate_colon
+ && self.may_recover()
&& (matches!(self.token.kind, token::CloseDelim(_) | token::Comma)
|| self.token.is_op())
{
prev_span: Span,
open_delim_span: Span,
) -> PResult<'a, ()> {
+ if !self.may_recover() {
+ return Ok(());
+ }
+
if self.token.kind == token::Comma {
if !self.sess.source_map().is_multiline(prev_span.until(self.token.span)) {
return Ok(());
lo: Span,
blk_mode: BlockCheckMode,
) -> PResult<'a, P<Expr>> {
- if self.is_array_like_block() {
+ if self.may_recover() && self.is_array_like_block() {
if let Some(arr) = self.maybe_suggest_brackets_instead_of_braces(lo) {
return Ok(arr);
}
// HACK: This is needed so we can detect whether we're inside a macro,
// where regular assumptions about what tokens can follow other tokens
// don't necessarily apply.
+ && self.may_recover()
+ // FIXME(Nilstrieb): Remove this check once `may_recover` actually stops recovery
&& self.subparser_name.is_none()
{
// It is likely that the closure body is a block but where the
};
while self.token != token::CloseDelim(close_delim) {
- if self.eat(&token::DotDot) {
+ if self.eat(&token::DotDot) || self.recover_struct_field_dots(close_delim) {
let exp_span = self.prev_token.span;
// We permit `.. }` on the left-hand side of a destructuring assignment.
if self.check(&token::CloseDelim(close_delim)) {
self.recover_stmt();
}
+ fn recover_struct_field_dots(&mut self, close_delim: Delimiter) -> bool {
+ if !self.look_ahead(1, |t| *t == token::CloseDelim(close_delim))
+ && self.eat(&token::DotDotDot)
+ {
+ // recover from typo of `...`, suggest `..`
+ let span = self.prev_token.span;
+ self.sess.emit_err(MissingDotDot { token_span: span, sugg_span: span });
+ return true;
+ }
+ false
+ }
+
/// Parses `ident (COLON expr)?`.
fn parse_expr_field(&mut self) -> PResult<'a, ExprField> {
let attrs = self.parse_outer_attributes()?;
macro_rules! maybe_recover_from_interpolated_ty_qpath {
($self: expr, $allow_qpath_recovery: expr) => {
if $allow_qpath_recovery
+ && $self.may_recover()
&& $self.look_ahead(1, |t| t == &token::ModSep)
&& let token::Interpolated(nt) = &$self.token.kind
&& let token::NtTy(ty) = &**nt
};
}
+#[derive(Clone, Copy)]
+pub enum Recovery {
+ Allowed,
+ Forbidden,
+}
+
#[derive(Clone)]
pub struct Parser<'a> {
pub sess: &'a ParseSess,
/// This allows us to recover when the user forget to add braces around
/// multiple statements in the closure body.
pub current_closure: Option<ClosureSpans>,
+ /// Whether the parser is allowed to do recovery.
+ /// This is disabled when parsing macro arguments, see #103534
+ pub recovery: Recovery,
}
-// This type is used a lot, e.g. it's cloned when matching many declarative macro rules. Make sure
+// This type is used a lot, e.g. it's cloned when matching many declarative macro rules with nonterminals. Make sure
// it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Parser<'_>, 328);
+rustc_data_structures::static_assert_size!(Parser<'_>, 336);
/// Stores span information about a closure.
#[derive(Clone)]
inner_attr_ranges: Default::default(),
},
current_closure: None,
+ recovery: Recovery::Allowed,
};
// Make parser point to the first token.
parser
}
+ pub fn forbid_recovery(mut self) -> Self {
+ self.recovery = Recovery::Forbidden;
+ self
+ }
+
+ /// Whether the parser is allowed to recover from broken code.
+ ///
+ /// If this returns false, recovering broken code into valid code (especially if this recovery does lookahead)
+ /// is not allowed. All recovery done by the parser must be gated behind this check.
+ ///
+ /// Technically, this only needs to restrict eager recovery by doing lookahead at more tokens.
+ /// But making the distinction is very subtle, and simply forbidding all recovery is a lot simpler to uphold.
+ fn may_recover(&self) -> bool {
+ matches!(self.recovery, Recovery::Allowed)
+ }
+
pub fn unexpected<T>(&mut self) -> PResult<'a, T> {
match self.expect_one_of(&[], &[]) {
Err(e) => Err(e),
};
fn find_skips(snippet: &str, is_raw: bool) -> Vec<usize> {
- let mut s = snippet.char_indices().peekable();
+ let mut s = snippet.char_indices();
let mut skips = vec![];
while let Some((pos, c)) = s.next() {
- match (c, s.peek()) {
+ match (c, s.clone().next()) {
// skip whitespace and empty lines ending in '\\'
('\\', Some((next_pos, '\n'))) if !is_raw => {
skips.push(pos);
- skips.push(*next_pos);
+ skips.push(next_pos);
let _ = s.next();
- while let Some((pos, c)) = s.peek() {
+ while let Some((pos, c)) = s.clone().next() {
if matches!(c, ' ' | '\n' | '\t') {
- skips.push(*pos);
+ skips.push(pos);
let _ = s.next();
} else {
break;
}
}
('\\', Some((next_pos, 'n' | 't' | 'r' | '0' | '\\' | '\'' | '\"'))) => {
- skips.push(*next_pos);
+ skips.push(next_pos);
let _ = s.next();
}
('\\', Some((_, 'x'))) if !is_raw => {
}
if let Some((next_pos, next_c)) = s.next() {
if next_c == '{' {
- skips.push(next_pos);
- let mut i = 0; // consume up to 6 hexanumeric chars + closing `}`
- while let (Some((next_pos, c)), true) = (s.next(), i < 7) {
- if c.is_digit(16) {
- skips.push(next_pos);
- } else if c == '}' {
- skips.push(next_pos);
- break;
- } else {
- break;
- }
- i += 1;
+ // consume up to 6 hexanumeric chars
+ let digits_len =
+ s.clone().take(6).take_while(|(_, c)| c.is_digit(16)).count();
+
+ let len_utf8 = s
+ .as_str()
+ .get(..digits_len)
+ .and_then(|digits| u32::from_str_radix(digits, 16).ok())
+ .and_then(char::from_u32)
+ .map_or(1, char::len_utf8);
+
+ // Skip the digits, for chars that encode to more than 1 utf-8 byte
+ // exclude as many digits as it is greater than 1 byte
+ //
+ // So for a 3 byte character, exclude 2 digits
+ let required_skips =
+ digits_len.saturating_sub(len_utf8.saturating_sub(1));
+
+ // skip '{' and '}' also
+ for pos in (next_pos..).take(required_skips + 2) {
+ skips.push(pos)
}
+
+ s.nth(digits_len);
} else if next_c.is_digit(16) {
skips.push(next_pos);
// We suggest adding `{` and `}` when appropriate, accept it here as if
// so this lets us continue to run them while maintaining backwards compatibility.
// In the long run, the checks should be harmonized.
if let ItemKind::Macro(ref macro_def, _) = item.kind {
- let def_id = item.def_id.to_def_id();
+ let def_id = item.owner_id.to_def_id();
if macro_def.macro_rules && !self.tcx.has_attr(def_id, sym::macro_export) {
check_non_exported_macro_for_invalid_attrs(self.tcx, item);
}
use itertools::Itertools;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::{pluralize, Applicability, MultiSpan};
+use rustc_errors::MultiSpan;
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Node, PatKind, TyKind};
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use rustc_middle::middle::privacy::AccessLevel;
+use rustc_middle::middle::privacy::Level;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, DefIdTree, TyCtxt};
use rustc_session::lint;
use rustc_span::symbol::{sym, Symbol};
use std::mem;
-use crate::errors::UselessAssignment;
+use crate::errors::{
+ ChangeFieldsToBeOfUnitType, IgnoredDerivedImpls, MultipleDeadCodes, ParentInfo,
+ UselessAssignment,
+};
// Any local node that may call something in its body block should be
// explored. For example, if it's a live Node::Item that is a
}
fn visit_node(&mut self, node: Node<'tcx>) {
- if let Node::ImplItem(hir::ImplItem { def_id, .. }) = node
- && self.should_ignore_item(def_id.to_def_id())
+ if let Node::ImplItem(hir::ImplItem { owner_id, .. }) = node
+ && self.should_ignore_item(owner_id.to_def_id())
{
return;
}
match node {
Node::Item(item) => match item.kind {
hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => {
- let def = self.tcx.adt_def(item.def_id);
+ let def = self.tcx.adt_def(item.owner_id);
self.repr_has_repr_c = def.repr().c();
self.repr_has_repr_simd = def.repr().simd();
intravisit::walk_trait_item(self, trait_item);
}
Node::ImplItem(impl_item) => {
- let item = self.tcx.local_parent(impl_item.def_id.def_id);
+ let item = self.tcx.local_parent(impl_item.owner_id.def_id);
if self.tcx.impl_trait_ref(item).is_none() {
//// If it's a type whose items are live, then it's live, too.
//// This is done to handle the case where, for example, the static
return true;
}
- // (To be) stable attribute for #[lang = "oom"]
- if tcx.sess.contains_name(attrs, sym::alloc_error_handler) {
- return true;
- }
-
let def_id = tcx.hir().local_def_id(id);
if tcx.def_kind(def_id).has_codegen_attrs() {
let cg_attrs = tcx.codegen_fn_attrs(def_id);
) {
let allow_dead_code = has_allow_dead_code_or_lang_attr(tcx, id.hir_id());
if allow_dead_code {
- worklist.push(id.def_id.def_id);
+ worklist.push(id.owner_id.def_id);
}
- match tcx.def_kind(id.def_id) {
+ match tcx.def_kind(id.owner_id) {
DefKind::Enum => {
let item = tcx.hir().item(id);
if let hir::ItemKind::Enum(ref enum_def, _) = item.kind {
}
}
DefKind::Impl => {
- let of_trait = tcx.impl_trait_ref(id.def_id);
+ let of_trait = tcx.impl_trait_ref(id.owner_id);
if of_trait.is_some() {
- worklist.push(id.def_id.def_id);
+ worklist.push(id.owner_id.def_id);
}
// get DefIds from another query
let local_def_ids = tcx
- .associated_item_def_ids(id.def_id)
+ .associated_item_def_ids(id.owner_id)
.iter()
.filter_map(|def_id| def_id.as_local());
if let hir::ItemKind::Struct(ref variant_data, _) = item.kind
&& let Some(ctor_hir_id) = variant_data.ctor_hir_id()
{
- struct_constructors.insert(tcx.hir().local_def_id(ctor_hir_id), item.def_id.def_id);
+ struct_constructors.insert(tcx.hir().local_def_id(ctor_hir_id), item.owner_id.def_id);
}
}
DefKind::GlobalAsm => {
// global_asm! is always live.
- worklist.push(id.def_id.def_id);
+ worklist.push(id.owner_id.def_id);
}
_ => {}
}
fn check_trait_item<'tcx>(tcx: TyCtxt<'tcx>, worklist: &mut Vec<LocalDefId>, id: hir::TraitItemId) {
use hir::TraitItemKind::{Const, Fn};
- if matches!(tcx.def_kind(id.def_id), DefKind::AssocConst | DefKind::AssocFn) {
+ if matches!(tcx.def_kind(id.owner_id), DefKind::AssocConst | DefKind::AssocFn) {
let trait_item = tcx.hir().trait_item(id);
if matches!(trait_item.kind, Const(_, Some(_)) | Fn(_, hir::TraitFn::Provided(_)))
&& has_allow_dead_code_or_lang_attr(tcx, trait_item.hir_id())
{
- worklist.push(trait_item.def_id.def_id);
+ worklist.push(trait_item.owner_id.def_id);
}
}
}
worklist: &mut Vec<LocalDefId>,
id: hir::ForeignItemId,
) {
- if matches!(tcx.def_kind(id.def_id), DefKind::Static(_) | DefKind::Fn)
+ if matches!(tcx.def_kind(id.owner_id), DefKind::Static(_) | DefKind::Fn)
&& has_allow_dead_code_or_lang_attr(tcx, id.hir_id())
{
- worklist.push(id.def_id.def_id);
+ worklist.push(id.owner_id.def_id);
}
}
fn create_and_seed_worklist<'tcx>(
tcx: TyCtxt<'tcx>,
) -> (Vec<LocalDefId>, FxHashMap<LocalDefId, LocalDefId>) {
- let access_levels = &tcx.privacy_access_levels(());
+ let effective_visibilities = &tcx.effective_visibilities(());
// see `MarkSymbolVisitor::struct_constructors`
let mut struct_constructors = Default::default();
- let mut worklist = access_levels
+ let mut worklist = effective_visibilities
.iter()
.filter_map(|(&id, effective_vis)| {
- effective_vis.is_public_at_level(AccessLevel::Reachable).then_some(id)
+ effective_vis.is_public_at_level(Level::Reachable).then_some(id)
})
// Seed entry point
.chain(tcx.entry_fn(()).and_then(|(def_id, _)| def_id.as_local()))
parent_item: Option<LocalDefId>,
is_positional: bool,
) {
- if let Some(&first_id) = dead_codes.first() {
- let tcx = self.tcx;
- let names: Vec<_> = dead_codes
- .iter()
- .map(|&def_id| tcx.item_name(def_id.to_def_id()).to_string())
- .collect();
- let spans: Vec<_> = dead_codes
- .iter()
- .map(|&def_id| match tcx.def_ident_span(def_id) {
- Some(s) => s.with_ctxt(tcx.def_span(def_id).ctxt()),
- None => tcx.def_span(def_id),
+ let Some(&first_id) = dead_codes.first() else {
+ return;
+ };
+ let tcx = self.tcx;
+ let names: Vec<_> =
+ dead_codes.iter().map(|&def_id| tcx.item_name(def_id.to_def_id())).collect();
+ let spans: Vec<_> = dead_codes
+ .iter()
+ .map(|&def_id| match tcx.def_ident_span(def_id) {
+ Some(s) => s.with_ctxt(tcx.def_span(def_id).ctxt()),
+ None => tcx.def_span(def_id),
+ })
+ .collect();
+
+ let descr = tcx.def_kind(first_id).descr(first_id.to_def_id());
+ let num = dead_codes.len();
+ let multiple = num > 6;
+ let name_list = names.into();
+
+ let lint = if is_positional {
+ lint::builtin::UNUSED_TUPLE_STRUCT_FIELDS
+ } else {
+ lint::builtin::DEAD_CODE
+ };
+
+ let parent_info = if let Some(parent_item) = parent_item {
+ let parent_descr = tcx.def_kind(parent_item).descr(parent_item.to_def_id());
+ Some(ParentInfo {
+ num,
+ descr,
+ parent_descr,
+ span: tcx.def_ident_span(parent_item).unwrap(),
+ })
+ } else {
+ None
+ };
+
+ let encl_def_id = parent_item.unwrap_or(first_id);
+ let ignored_derived_impls =
+ if let Some(ign_traits) = self.ignored_derived_traits.get(&encl_def_id) {
+ let trait_list = ign_traits
+ .iter()
+ .map(|(trait_id, _)| self.tcx.item_name(*trait_id))
+ .collect::<Vec<_>>();
+ let trait_list_len = trait_list.len();
+ Some(IgnoredDerivedImpls {
+ name: self.tcx.item_name(encl_def_id.to_def_id()),
+ trait_list: trait_list.into(),
+ trait_list_len,
})
- .collect();
-
- let descr = tcx.def_kind(first_id).descr(first_id.to_def_id());
- let span_len = dead_codes.len();
- let names = match &names[..] {
- _ if span_len > 6 => String::new(),
- [name] => format!("`{name}` "),
- [names @ .., last] => {
- format!(
- "{} and `{last}` ",
- names.iter().map(|name| format!("`{name}`")).join(", ")
- )
- }
- [] => unreachable!(),
+ } else {
+ None
};
- let msg = format!(
- "{these}{descr}{s} {names}{are} never {participle}",
- these = if span_len > 6 { "multiple " } else { "" },
- s = pluralize!(span_len),
- are = pluralize!("is", span_len),
- );
-
- tcx.struct_span_lint_hir(
- if is_positional {
- lint::builtin::UNUSED_TUPLE_STRUCT_FIELDS
- } else {
- lint::builtin::DEAD_CODE
- },
- tcx.hir().local_def_id_to_hir_id(first_id),
- MultiSpan::from_spans(spans.clone()),
- msg,
- |err| {
- if is_positional {
- err.multipart_suggestion(
- &format!(
- "consider changing the field{s} to be of unit type to \
- suppress this warning while preserving the field \
- numbering, or remove the field{s}",
- s = pluralize!(span_len)
- ),
- spans.iter().map(|sp| (*sp, "()".to_string())).collect(),
- // "HasPlaceholders" because applying this fix by itself isn't
- // enough: All constructor calls have to be adjusted as well
- Applicability::HasPlaceholders,
- );
- }
- if let Some(parent_item) = parent_item {
- let parent_descr = tcx.def_kind(parent_item).descr(parent_item.to_def_id());
- err.span_label(
- tcx.def_ident_span(parent_item).unwrap(),
- format!("{descr}{s} in this {parent_descr}", s = pluralize!(span_len)),
- );
- }
+ let diag = if is_positional {
+ MultipleDeadCodes::UnusedTupleStructFields {
+ multiple,
+ num,
+ descr,
+ participle,
+ name_list,
+ change_fields_suggestion: ChangeFieldsToBeOfUnitType { num, spans: spans.clone() },
+ parent_info,
+ ignored_derived_impls,
+ }
+ } else {
+ MultipleDeadCodes::DeadCodes {
+ multiple,
+ num,
+ descr,
+ participle,
+ name_list,
+ parent_info,
+ ignored_derived_impls,
+ }
+ };
- let encl_def_id = parent_item.unwrap_or(first_id);
- if let Some(ign_traits) = self.ignored_derived_traits.get(&encl_def_id) {
- let traits_str = ign_traits
- .iter()
- .map(|(trait_id, _)| format!("`{}`", self.tcx.item_name(*trait_id)))
- .collect::<Vec<_>>()
- .join(" and ");
- let plural_s = pluralize!(ign_traits.len());
- let article = if ign_traits.len() > 1 { "" } else { "a " };
- let is_are = if ign_traits.len() > 1 { "these are" } else { "this is" };
- let msg = format!(
- "`{}` has {}derived impl{} for the trait{} {}, but {} \
- intentionally ignored during dead code analysis",
- self.tcx.item_name(encl_def_id.to_def_id()),
- article,
- plural_s,
- plural_s,
- traits_str,
- is_are
- );
- err.note(&msg);
- }
- err
- },
- );
- }
+ self.tcx.emit_spanned_lint(
+ lint,
+ tcx.hir().local_def_id_to_hir_id(first_id),
+ MultiSpan::from_spans(spans.clone()),
+ diag,
+ );
}
fn warn_dead_fields_and_variants(
let module_items = tcx.hir_module_items(module);
for item in module_items.items() {
- if !live_symbols.contains(&item.def_id.def_id) {
- let parent = tcx.local_parent(item.def_id.def_id);
+ if !live_symbols.contains(&item.owner_id.def_id) {
+ let parent = tcx.local_parent(item.owner_id.def_id);
if parent != module && !live_symbols.contains(&parent) {
// We already have diagnosed something.
continue;
}
- visitor.check_definition(item.def_id.def_id);
+ visitor.check_definition(item.owner_id.def_id);
continue;
}
- let def_kind = tcx.def_kind(item.def_id);
+ let def_kind = tcx.def_kind(item.owner_id);
if let DefKind::Struct | DefKind::Union | DefKind::Enum = def_kind {
- let adt = tcx.adt_def(item.def_id);
+ let adt = tcx.adt_def(item.owner_id);
let mut dead_variants = Vec::new();
for variant in adt.variants() {
}
visitor.warn_dead_fields_and_variants(
- item.def_id.def_id,
+ item.owner_id.def_id,
"constructed",
dead_variants,
false,
}
for impl_item in module_items.impl_items() {
- visitor.check_definition(impl_item.def_id.def_id);
+ visitor.check_definition(impl_item.owner_id.def_id);
}
for foreign_item in module_items.foreign_items() {
- visitor.check_definition(foreign_item.def_id.def_id);
+ visitor.check_definition(foreign_item.owner_id.def_id);
}
// We do not warn trait items.
let crate_items = tcx.hir_crate_items(());
for id in crate_items.items() {
- observe_item(tcx, &mut diagnostic_items, id.def_id.def_id);
+ observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id);
}
for id in crate_items.trait_items() {
- observe_item(tcx, &mut diagnostic_items, id.def_id.def_id);
+ observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id);
}
for id in crate_items.impl_items() {
- observe_item(tcx, &mut diagnostic_items, id.def_id.def_id);
+ observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id);
}
for id in crate_items.foreign_items() {
- observe_item(tcx, &mut diagnostic_items, id.def_id.def_id);
+ observe_item(tcx, &mut diagnostic_items, id.owner_id.def_id);
}
diagnostic_items
} else if ctxt.tcx.sess.contains_name(attrs, sym::rustc_main) {
EntryPointType::RustcMainAttr
} else {
- if let Some(name) = ctxt.tcx.opt_item_name(id.def_id.to_def_id())
+ if let Some(name) = ctxt.tcx.opt_item_name(id.owner_id.to_def_id())
&& name == sym::main {
if at_root {
// This is a top-level function so can be `main`.
}
fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
- let at_root = ctxt.tcx.opt_local_parent(id.def_id.def_id) == Some(CRATE_DEF_ID);
+ let at_root = ctxt.tcx.opt_local_parent(id.owner_id.def_id) == Some(CRATE_DEF_ID);
match entry_point_type(ctxt, id, at_root) {
EntryPointType::None => {
ctxt.tcx.sess.emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe });
}
}
- _ if !matches!(ctxt.tcx.def_kind(id.def_id), DefKind::Fn) => {
+ _ if !matches!(ctxt.tcx.def_kind(id.owner_id), DefKind::Fn) => {
for attr in [sym::start, sym::rustc_main] {
if let Some(span) = attr_span_by_symbol(ctxt, id, attr) {
ctxt.tcx.sess.emit_err(AttrOnlyInFunctions { span, attr });
if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
ctxt.tcx.sess.emit_err(AttrOnlyOnRootMain { span, attr: sym::unix_sigpipe });
}
- ctxt.non_main_fns.push(ctxt.tcx.def_span(id.def_id));
+ ctxt.non_main_fns.push(ctxt.tcx.def_span(id.owner_id));
}
EntryPointType::RustcMainAttr => {
if ctxt.attr_main_fn.is_none() {
- ctxt.attr_main_fn = Some((id.def_id.def_id, ctxt.tcx.def_span(id.def_id)));
+ ctxt.attr_main_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id)));
} else {
ctxt.tcx.sess.emit_err(MultipleRustcMain {
- span: ctxt.tcx.def_span(id.def_id.to_def_id()),
+ span: ctxt.tcx.def_span(id.owner_id.to_def_id()),
first: ctxt.attr_main_fn.unwrap().1,
- additional: ctxt.tcx.def_span(id.def_id.to_def_id()),
+ additional: ctxt.tcx.def_span(id.owner_id.to_def_id()),
});
}
}
ctxt.tcx.sess.emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe });
}
if ctxt.start_fn.is_none() {
- ctxt.start_fn = Some((id.def_id.def_id, ctxt.tcx.def_span(id.def_id)));
+ ctxt.start_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id)));
} else {
ctxt.tcx.sess.emit_err(MultipleStartFunctions {
- span: ctxt.tcx.def_span(id.def_id),
- labeled: ctxt.tcx.def_span(id.def_id.to_def_id()),
+ span: ctxt.tcx.def_span(id.owner_id),
+ labeled: ctxt.tcx.def_span(id.owner_id.to_def_id()),
previous: ctxt.start_fn.unwrap().1,
});
}
};
use rustc_ast::Label;
-use rustc_errors::{error_code, Applicability, ErrorGuaranteed, IntoDiagnostic, MultiSpan};
+use rustc_errors::{
+ error_code, Applicability, DiagnosticSymbolList, ErrorGuaranteed, IntoDiagnostic, MultiSpan,
+};
use rustc_hir::{self as hir, ExprKind, Target};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::ty::{MainDefinition, Ty};
#[note(no_op_note)]
pub struct DocTestUnknownSpotlight {
pub path: String,
- #[suggestion_short(applicability = "machine-applicable", code = "notable_trait")]
+ #[suggestion(style = "short", applicability = "machine-applicable", code = "notable_trait")]
pub span: Span,
}
#[diag(passes_missing_panic_handler)]
pub struct MissingPanicHandler;
-#[derive(Diagnostic)]
-#[diag(passes_alloc_func_required)]
-pub struct AllocFuncRequired;
-
-#[derive(Diagnostic)]
-#[diag(passes_missing_alloc_error_handler)]
-pub struct MissingAllocErrorHandler;
-
#[derive(Diagnostic)]
#[diag(passes_missing_lang_item)]
#[note]
}
impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel {
+ #[track_caller]
fn into_diagnostic(
self,
handler: &'_ rustc_errors::Handler,
}
impl<'a> IntoDiagnostic<'_> for BreakNonLoop<'a> {
+ #[track_caller]
fn into_diagnostic(
self,
handler: &rustc_errors::Handler,
#[label]
pub span: Span,
pub name: &'a str,
+ pub is_break: bool,
}
#[derive(Diagnostic)]
}
impl IntoDiagnostic<'_> for NakedFunctionsAsmBlock {
+ #[track_caller]
fn into_diagnostic(
self,
handler: &rustc_errors::Handler,
}
impl<'a> IntoDiagnostic<'a> for NoMainErr {
+ #[track_caller]
fn into_diagnostic(
self,
handler: &'a rustc_errors::Handler,
}
impl IntoDiagnostic<'_> for DuplicateLangItem {
+ #[track_caller]
fn into_diagnostic(
self,
handler: &rustc_errors::Handler,
#[label]
pub const_span: Span,
}
+
+#[derive(LintDiagnostic)]
+pub enum MultipleDeadCodes<'tcx> {
+ #[diag(passes_dead_codes)]
+ DeadCodes {
+ multiple: bool,
+ num: usize,
+ descr: &'tcx str,
+ participle: &'tcx str,
+ name_list: DiagnosticSymbolList,
+ #[subdiagnostic]
+ parent_info: Option<ParentInfo<'tcx>>,
+ #[subdiagnostic]
+ ignored_derived_impls: Option<IgnoredDerivedImpls>,
+ },
+ #[diag(passes_dead_codes)]
+ UnusedTupleStructFields {
+ multiple: bool,
+ num: usize,
+ descr: &'tcx str,
+ participle: &'tcx str,
+ name_list: DiagnosticSymbolList,
+ #[subdiagnostic]
+ change_fields_suggestion: ChangeFieldsToBeOfUnitType,
+ #[subdiagnostic]
+ parent_info: Option<ParentInfo<'tcx>>,
+ #[subdiagnostic]
+ ignored_derived_impls: Option<IgnoredDerivedImpls>,
+ },
+}
+
+#[derive(Subdiagnostic)]
+#[label(passes_parent_info)]
+pub struct ParentInfo<'tcx> {
+ pub num: usize,
+ pub descr: &'tcx str,
+ pub parent_descr: &'tcx str,
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[note(passes_ignored_derived_impls)]
+pub struct IgnoredDerivedImpls {
+ pub name: Symbol,
+ pub trait_list: DiagnosticSymbolList,
+ pub trait_list_len: usize,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(passes_change_fields_to_be_of_unit_type, applicability = "has-placeholders")]
+pub struct ChangeFieldsToBeOfUnitType {
+ pub num: usize,
+ #[suggestion_part(code = "()")]
+ pub spans: Vec<Span>,
+}
fn visit_item(&mut self, i: &'hir hir::Item<'hir>) {
let mut inner_visitor = self.new_visitor(self.hir_map);
- inner_visitor.check(i.def_id, |this| intravisit::walk_item(this, i));
+ inner_visitor.check(i.owner_id, |this| intravisit::walk_item(this, i));
}
fn visit_id(&mut self, hir_id: HirId) {
fn visit_foreign_item(&mut self, i: &'hir hir::ForeignItem<'hir>) {
let mut inner_visitor = self.new_visitor(self.hir_map);
- inner_visitor.check(i.def_id, |this| intravisit::walk_foreign_item(this, i));
+ inner_visitor.check(i.owner_id, |this| intravisit::walk_foreign_item(this, i));
}
fn visit_trait_item(&mut self, i: &'hir hir::TraitItem<'hir>) {
let mut inner_visitor = self.new_visitor(self.hir_map);
- inner_visitor.check(i.def_id, |this| intravisit::walk_trait_item(this, i));
+ inner_visitor.check(i.owner_id, |this| intravisit::walk_trait_item(this, i));
}
fn visit_impl_item(&mut self, i: &'hir hir::ImplItem<'hir>) {
let mut inner_visitor = self.new_visitor(self.hir_map);
- inner_visitor.check(i.def_id, |this| intravisit::walk_impl_item(this, i));
+ inner_visitor.check(i.owner_id, |this| intravisit::walk_impl_item(this, i));
}
}
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
-use rustc_hir::lang_items::{extract, GenericRequirement, ITEM_REFS};
+use rustc_hir::lang_items::{extract, GenericRequirement};
use rustc_hir::{HirId, LangItem, LanguageItems, Target};
use rustc_middle::ty::TyCtxt;
use rustc_session::cstore::ExternCrate;
fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId) {
let attrs = self.tcx.hir().attrs(hir_id);
if let Some((name, span)) = extract(&attrs) {
- match ITEM_REFS.get(&name).cloned() {
+ match LangItem::from_name(name) {
// Known lang item with attribute on correct target.
- Some((item_index, expected_target)) if actual_target == expected_target => {
- self.collect_item_extended(item_index, hir_id, span);
+ Some(lang_item) if actual_target == lang_item.target() => {
+ self.collect_item_extended(lang_item, hir_id, span);
}
// Known lang item with attribute on incorrect target.
- Some((_, expected_target)) => {
+ Some(lang_item) => {
self.tcx.sess.emit_err(LangItemOnIncorrectTarget {
span,
name,
- expected_target,
+ expected_target: lang_item.target(),
actual_target,
});
}
}
}
- fn collect_item(&mut self, item_index: usize, item_def_id: DefId) {
+ fn collect_item(&mut self, lang_item: LangItem, item_def_id: DefId) {
// Check for duplicates.
- if let Some(original_def_id) = self.items.items[item_index] {
+ if let Some(original_def_id) = self.items.get(lang_item) {
if original_def_id != item_def_id {
let local_span = self.tcx.hir().span_if_local(item_def_id);
- let lang_item_name = LangItem::from_u32(item_index as u32).unwrap().name();
+ let lang_item_name = lang_item.name();
let crate_name = self.tcx.crate_name(item_def_id.krate);
let mut dependency_of = Empty;
let is_local = item_def_id.is_local();
}
// Matched.
- self.items.items[item_index] = Some(item_def_id);
- if let Some(group) = LangItem::from_u32(item_index as u32).unwrap().group() {
- self.items.groups[group as usize].push(item_def_id);
- }
+ self.items.set(lang_item, item_def_id);
}
// Like collect_item() above, but also checks whether the lang item is declared
// with the right number of generic arguments.
- fn collect_item_extended(&mut self, item_index: usize, hir_id: HirId, span: Span) {
+ fn collect_item_extended(&mut self, lang_item: LangItem, hir_id: HirId, span: Span) {
let item_def_id = self.tcx.hir().local_def_id(hir_id).to_def_id();
- let lang_item = LangItem::from_u32(item_index as u32).unwrap();
let name = lang_item.name();
// Now check whether the lang_item has the expected number of generic
}
}
- self.collect_item(item_index, item_def_id);
+ self.collect_item(lang_item, item_def_id);
}
}
// Collect lang items in other crates.
for &cnum in tcx.crates(()).iter() {
- for &(def_id, item_index) in tcx.defined_lang_items(cnum).iter() {
- collector.collect_item(item_index, def_id);
+ for &(def_id, lang_item) in tcx.defined_lang_items(cnum).iter() {
+ collector.collect_item(lang_item, def_id);
}
}
let crate_items = tcx.hir_crate_items(());
for id in crate_items.items() {
- collector.check_for_lang(Target::from_def_kind(tcx.def_kind(id.def_id)), id.hir_id());
+ collector.check_for_lang(Target::from_def_kind(tcx.def_kind(id.owner_id)), id.hir_id());
- if matches!(tcx.def_kind(id.def_id), DefKind::Enum) {
+ if matches!(tcx.def_kind(id.owner_id), DefKind::Enum) {
let item = tcx.hir().item(id);
if let hir::ItemKind::Enum(def, ..) = &item.kind {
for variant in def.variants {
// if the `rustc_attrs` feature is not enabled, don't bother testing layout
for id in tcx.hir().items() {
if matches!(
- tcx.def_kind(id.def_id),
+ tcx.def_kind(id.owner_id),
DefKind::TyAlias | DefKind::Enum | DefKind::Struct | DefKind::Union
) {
- for attr in tcx.get_attrs(id.def_id.to_def_id(), sym::rustc_layout) {
- dump_layout_of(tcx, id.def_id.def_id, attr);
+ for attr in tcx.get_attrs(id.owner_id.to_def_id(), sym::rustc_layout) {
+ dump_layout_of(tcx, id.owner_id.def_id, attr);
}
}
}
//! This API is completely unstable and subject to change.
#![allow(rustc::potential_query_instability)]
-#![deny(rustc::untranslatable_diagnostic)]
-#![deny(rustc::diagnostic_outside_of_impl)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(iter_intersperse)]
#![feature(let_chains)]
self.sess.emit_err(BreakInsideAsyncBlock { span, closure_span, name });
}
Normal | AnonConst => {
- self.sess.emit_err(OutsideLoop { span, name });
+ self.sess.emit_err(OutsideLoop { span, name, is_break: name == "break" });
}
}
}
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::Node;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
-use rustc_middle::middle::privacy::{self, AccessLevel};
+use rustc_middle::middle::privacy::{self, Level};
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, DefIdTree, TyCtxt};
use rustc_session::config::CrateType;
match item.kind {
hir::ItemKind::Fn(ref sig, ..) if sig.header.is_const() => true,
hir::ItemKind::Impl { .. } | hir::ItemKind::Fn(..) => {
- let generics = tcx.generics_of(item.def_id);
+ let generics = tcx.generics_of(item.owner_id);
generics.requires_monomorphization(tcx)
}
_ => false,
impl_src: LocalDefId,
) -> bool {
let codegen_fn_attrs = tcx.codegen_fn_attrs(impl_item.hir_id().owner.to_def_id());
- let generics = tcx.generics_of(impl_item.def_id);
+ let generics = tcx.generics_of(impl_item.owner_id);
if codegen_fn_attrs.requests_inline() || generics.requires_monomorphization(tcx) {
return true;
}
if item_might_be_inlined(
self.tcx,
&item,
- self.tcx.codegen_fn_attrs(item.def_id),
+ self.tcx.codegen_fn_attrs(item.owner_id),
) {
self.visit_nested_body(body);
}
tcx: TyCtxt<'tcx>,
id: hir::ItemId,
worklist: &mut Vec<LocalDefId>,
- access_levels: &privacy::AccessLevels,
+ effective_visibilities: &privacy::EffectiveVisibilities,
) {
- if has_custom_linkage(tcx, id.def_id.def_id) {
- worklist.push(id.def_id.def_id);
+ if has_custom_linkage(tcx, id.owner_id.def_id) {
+ worklist.push(id.owner_id.def_id);
}
- if !matches!(tcx.def_kind(id.def_id), DefKind::Impl) {
+ if !matches!(tcx.def_kind(id.owner_id), DefKind::Impl) {
return;
}
if let hir::ItemKind::Impl(hir::Impl { of_trait: Some(ref trait_ref), ref items, .. }) =
item.kind
{
- if !access_levels.is_reachable(item.def_id.def_id) {
- worklist.extend(items.iter().map(|ii_ref| ii_ref.id.def_id.def_id));
+ if !effective_visibilities.is_reachable(item.owner_id.def_id) {
+ worklist.extend(items.iter().map(|ii_ref| ii_ref.id.owner_id.def_id));
let Res::Def(DefKind::Trait, trait_def_id) = trait_ref.path.res else {
unreachable!();
}
fn reachable_set<'tcx>(tcx: TyCtxt<'tcx>, (): ()) -> FxHashSet<LocalDefId> {
- let access_levels = &tcx.privacy_access_levels(());
+ let effective_visibilities = &tcx.effective_visibilities(());
let any_library =
tcx.sess.crate_types().iter().any(|ty| {
// If other crates link to us, they're going to expect to be able to
// use the lang items, so we need to be sure to mark them as
// exported.
- reachable_context.worklist = access_levels
+ reachable_context.worklist = effective_visibilities
.iter()
.filter_map(|(&id, effective_vis)| {
- effective_vis.is_public_at_level(AccessLevel::ReachableFromImplTrait).then_some(id)
+ effective_vis.is_public_at_level(Level::ReachableThroughImplTrait).then_some(id)
})
.collect::<Vec<_>>();
- for item in tcx.lang_items().items().iter() {
- if let Some(def_id) = *item {
- if let Some(def_id) = def_id.as_local() {
- reachable_context.worklist.push(def_id);
- }
+ for (_, def_id) in tcx.lang_items().iter() {
+ if let Some(def_id) = def_id.as_local() {
+ reachable_context.worklist.push(def_id);
}
}
{
let crate_items = tcx.hir_crate_items(());
for id in crate_items.items() {
- check_item(tcx, id, &mut reachable_context.worklist, access_levels);
+ check_item(tcx, id, &mut reachable_context.worklist, effective_visibilities);
}
for id in crate_items.impl_items() {
- if has_custom_linkage(tcx, id.def_id.def_id) {
- reachable_context.worklist.push(id.def_id.def_id);
+ if has_custom_linkage(tcx, id.owner_id.def_id) {
+ reachable_context.worklist.push(id.owner_id.def_id);
}
}
}
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
use rustc_middle::hir::nested_filter;
-use rustc_middle::middle::privacy::AccessLevels;
+use rustc_middle::middle::privacy::EffectiveVisibilities;
use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, Index};
use rustc_middle::ty::{query::Providers, TyCtxt};
use rustc_session::lint;
}
self.annotate(
- i.def_id.def_id,
+ i.owner_id.def_id,
i.span,
fn_sig,
kind,
};
self.annotate(
- ti.def_id.def_id,
+ ti.owner_id.def_id,
ti.span,
fn_sig,
AnnotationKind::Required,
};
self.annotate(
- ii.def_id.def_id,
+ ii.owner_id.def_id,
ii.span,
fn_sig,
kind,
fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
self.annotate(
- i.def_id.def_id,
+ i.owner_id.def_id,
i.span,
None,
AnnotationKind::Required,
struct MissingStabilityAnnotations<'tcx> {
tcx: TyCtxt<'tcx>,
- access_levels: &'tcx AccessLevels,
+ effective_visibilities: &'tcx EffectiveVisibilities,
}
impl<'tcx> MissingStabilityAnnotations<'tcx> {
fn check_missing_stability(&self, def_id: LocalDefId, span: Span) {
let stab = self.tcx.stability().local_stability(def_id);
- if !self.tcx.sess.opts.test && stab.is_none() && self.access_levels.is_reachable(def_id) {
+ if !self.tcx.sess.opts.test
+ && stab.is_none()
+ && self.effective_visibilities.is_reachable(def_id)
+ {
let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
self.tcx.sess.emit_err(MissingStabilityAttr { span, descr });
}
.lookup_stability(def_id)
.map_or(false, |stability| stability.level.is_stable());
let missing_const_stability_attribute = self.tcx.lookup_const_stability(def_id).is_none();
- let is_reachable = self.access_levels.is_reachable(def_id);
+ let is_reachable = self.effective_visibilities.is_reachable(def_id);
if is_const && is_stable && missing_const_stability_attribute && is_reachable {
let descr = self.tcx.def_kind(def_id).descr(def_id.to_def_id());
hir::ItemKind::Impl(hir::Impl { of_trait: None, .. })
| hir::ItemKind::ForeignMod { .. }
) {
- self.check_missing_stability(i.def_id.def_id, i.span);
+ self.check_missing_stability(i.owner_id.def_id, i.span);
}
// Ensure stable `const fn` have a const stability attribute.
- self.check_missing_const_stability(i.def_id.def_id, i.span);
+ self.check_missing_const_stability(i.owner_id.def_id, i.span);
intravisit::walk_item(self, i)
}
fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) {
- self.check_missing_stability(ti.def_id.def_id, ti.span);
+ self.check_missing_stability(ti.owner_id.def_id, ti.span);
intravisit::walk_trait_item(self, ti);
}
fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) {
let impl_def_id = self.tcx.hir().get_parent_item(ii.hir_id());
if self.tcx.impl_trait_ref(impl_def_id).is_none() {
- self.check_missing_stability(ii.def_id.def_id, ii.span);
- self.check_missing_const_stability(ii.def_id.def_id, ii.span);
+ self.check_missing_stability(ii.owner_id.def_id, ii.span);
+ self.check_missing_const_stability(ii.owner_id.def_id, ii.span);
}
intravisit::walk_impl_item(self, ii);
}
}
fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) {
- self.check_missing_stability(i.def_id.def_id, i.span);
+ self.check_missing_stability(i.owner_id.def_id, i.span);
intravisit::walk_foreign_item(self, i);
}
// Note that we don't need to `check_missing_stability` for default generic parameters,
return;
}
- let Some(cnum) = self.tcx.extern_mod_stmt_cnum(item.def_id.def_id) else {
+ let Some(cnum) = self.tcx.extern_mod_stmt_cnum(item.owner_id.def_id) else {
return;
};
let def_id = cnum.as_def_id();
}
for impl_item_ref in *items {
- let impl_item = self.tcx.associated_item(impl_item_ref.id.def_id);
+ let impl_item = self.tcx.associated_item(impl_item_ref.id.owner_id);
if let Some(def_id) = impl_item.trait_item_def_id {
// Pass `None` to skip deprecation warnings.
let is_staged_api =
tcx.sess.opts.unstable_opts.force_unstable_if_unmarked || tcx.features().staged_api;
if is_staged_api {
- let access_levels = &tcx.privacy_access_levels(());
- let mut missing = MissingStabilityAnnotations { tcx, access_levels };
+ let effective_visibilities = &tcx.effective_visibilities(());
+ let mut missing = MissingStabilityAnnotations { tcx, effective_visibilities };
missing.check_missing_stability(CRATE_DEF_ID, tcx.hir().span(CRATE_HIR_ID));
tcx.hir().walk_toplevel_module(&mut missing);
tcx.hir().visit_all_item_likes_in_crate(&mut missing);
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::lang_items::{self, LangItem};
-use rustc_hir::weak_lang_items::WEAK_ITEMS_REFS;
+use rustc_hir::weak_lang_items::WEAK_LANG_ITEMS;
use rustc_middle::middle::lang_items::required;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::CrateType;
-use crate::errors::{
- AllocFuncRequired, MissingAllocErrorHandler, MissingLangItem, MissingPanicHandler,
- UnknownExternLangItem,
-};
+use crate::errors::{MissingLangItem, MissingPanicHandler, UnknownExternLangItem};
/// Checks the crate for usage of weak lang items, returning a vector of all the
/// language items required by this crate, but not defined yet.
for id in crate_items.foreign_items() {
let attrs = tcx.hir().attrs(id.hir_id());
if let Some((lang_item, _)) = lang_items::extract(attrs) {
- if let Some(&item) = WEAK_ITEMS_REFS.get(&lang_item) {
- if items.require(item).is_err() {
+ if let Some(item) = LangItem::from_name(lang_item) && item.is_weak() {
+ if items.get(item).is_none() {
items.missing.push(item);
}
} else {
- let span = tcx.def_span(id.def_id);
+ let span = tcx.def_span(id.owner_id);
tcx.sess.emit_err(UnknownExternLangItem { span, lang_item });
}
}
}
}
- for (name, &item) in WEAK_ITEMS_REFS.iter() {
- if missing.contains(&item) && required(tcx, item) && items.require(item).is_err() {
+ for &item in WEAK_LANG_ITEMS.iter() {
+ if missing.contains(&item) && required(tcx, item) && items.get(item).is_none() {
if item == LangItem::PanicImpl {
tcx.sess.emit_err(MissingPanicHandler);
- } else if item == LangItem::Oom {
- if !tcx.features().default_alloc_error_handler {
- tcx.sess.emit_err(AllocFuncRequired);
- tcx.sess.emit_note(MissingAllocErrorHandler);
- }
} else {
- tcx.sess.emit_err(MissingLangItem { name: *name });
+ tcx.sess.emit_err(MissingLangItem { name: item.name() });
}
}
}
use rustc_hir::{AssocItemKind, HirIdSet, ItemId, Node, PatKind};
use rustc_middle::bug;
use rustc_middle::hir::nested_filter;
-use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
+use rustc_middle::middle::privacy::{EffectiveVisibilities, Level};
use rustc_middle::span_bug;
use rustc_middle::ty::abstract_const::{walk_abstract_const, AbstractConst, Node as ACNode};
use rustc_middle::ty::query::Providers;
struct FindMin<'a, 'tcx, VL: VisibilityLike> {
tcx: TyCtxt<'tcx>,
- access_levels: &'a AccessLevels,
+ effective_visibilities: &'a EffectiveVisibilities,
min: VL,
}
// Returns an over-approximation (`skip_assoc_tys` = true) of visibility due to
// associated types for which we can't determine visibility precisely.
- fn of_impl(def_id: LocalDefId, tcx: TyCtxt<'_>, access_levels: &AccessLevels) -> Self {
- let mut find = FindMin { tcx, access_levels, min: Self::MAX };
+ fn of_impl(
+ def_id: LocalDefId,
+ tcx: TyCtxt<'_>,
+ effective_visibilities: &EffectiveVisibilities,
+ ) -> Self {
+ let mut find = FindMin { tcx, effective_visibilities, min: Self::MAX };
find.visit(tcx.type_of(def_id));
if let Some(trait_ref) = tcx.impl_trait_ref(def_id) {
find.visit_trait(trait_ref);
min(find.tcx.local_visibility(def_id), find.min, find.tcx)
}
}
-impl VisibilityLike for Option<AccessLevel> {
- const MAX: Self = Some(AccessLevel::Public);
+impl VisibilityLike for Option<Level> {
+ const MAX: Self = Some(Level::Direct);
// Type inference is very smart sometimes.
// It can make an impl reachable even some components of its type or trait are unreachable.
// E.g. methods of `impl ReachableTrait<UnreachableTy> for ReachableTy<UnreachableTy> { ... }`
// (which require reaching the `DefId`s in them).
const SHALLOW: bool = true;
fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self {
- cmp::min(find.access_levels.get_access_level(def_id), find.min)
+ cmp::min(find.effective_visibilities.public_at_level(def_id), find.min)
}
}
struct EmbargoVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
- /// Accessibility levels for reachable nodes.
- access_levels: AccessLevels,
+ /// Effective visibilities for reachable nodes.
+ effective_visibilities: EffectiveVisibilities,
/// A set of pairs corresponding to modules, where the first module is
/// reachable via a macro that's defined in the second module. This cannot
/// be represented as reachable because it can't handle the following case:
/// n::p::f()
/// }
macro_reachable: FxHashSet<(LocalDefId, LocalDefId)>,
- /// Previous accessibility level; `None` means unreachable.
- prev_level: Option<AccessLevel>,
+ /// Previous visibility level; `None` means unreachable.
+ prev_level: Option<Level>,
/// Has something changed in the level map?
changed: bool,
}
struct ReachEverythingInTheInterfaceVisitor<'a, 'tcx> {
- access_level: Option<AccessLevel>,
+ level: Option<Level>,
item_def_id: LocalDefId,
ev: &'a mut EmbargoVisitor<'tcx>,
}
impl<'tcx> EmbargoVisitor<'tcx> {
- fn get(&self, def_id: LocalDefId) -> Option<AccessLevel> {
- self.access_levels.get_access_level(def_id)
+ fn get(&self, def_id: LocalDefId) -> Option<Level> {
+ self.effective_visibilities.public_at_level(def_id)
}
- fn update_with_hir_id(
- &mut self,
- hir_id: hir::HirId,
- level: Option<AccessLevel>,
- ) -> Option<AccessLevel> {
+ fn update_with_hir_id(&mut self, hir_id: hir::HirId, level: Option<Level>) -> Option<Level> {
let def_id = self.tcx.hir().local_def_id(hir_id);
self.update(def_id, level)
}
/// Updates node level and returns the updated level.
- fn update(&mut self, def_id: LocalDefId, level: Option<AccessLevel>) -> Option<AccessLevel> {
+ fn update(&mut self, def_id: LocalDefId, level: Option<Level>) -> Option<Level> {
let old_level = self.get(def_id);
- // Accessibility levels can only grow.
+ // Visibility levels can only grow.
if level > old_level {
- self.access_levels.set_access_level(
+ self.effective_visibilities.set_public_at_level(
def_id,
|| ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id)),
level.unwrap(),
fn reach(
&mut self,
def_id: LocalDefId,
- access_level: Option<AccessLevel>,
+ level: Option<Level>,
) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
ReachEverythingInTheInterfaceVisitor {
- access_level: cmp::min(access_level, Some(AccessLevel::Reachable)),
+ level: cmp::min(level, Some(Level::Reachable)),
item_def_id: def_id,
ev: self,
}
fn update_macro_reachable_mod(&mut self, module_def_id: LocalDefId, defining_mod: LocalDefId) {
let module = self.tcx.hir().get_module(module_def_id).0;
for item_id in module.item_ids {
- let def_kind = self.tcx.def_kind(item_id.def_id);
- let vis = self.tcx.local_visibility(item_id.def_id.def_id);
- self.update_macro_reachable_def(item_id.def_id.def_id, def_kind, vis, defining_mod);
+ let def_kind = self.tcx.def_kind(item_id.owner_id);
+ let vis = self.tcx.local_visibility(item_id.owner_id.def_id);
+ self.update_macro_reachable_def(item_id.owner_id.def_id, def_kind, vis, defining_mod);
}
if let Some(exports) = self.tcx.module_reexports(module_def_id) {
for export in exports {
vis: ty::Visibility,
module: LocalDefId,
) {
- let level = Some(AccessLevel::Reachable);
+ let level = Some(Level::Reachable);
if vis.is_public() {
self.update(def_id, level);
}
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
let item_level = match item.kind {
hir::ItemKind::Impl { .. } => {
- let impl_level = Option::<AccessLevel>::of_impl(
- item.def_id.def_id,
+ let impl_level = Option::<Level>::of_impl(
+ item.owner_id.def_id,
self.tcx,
- &self.access_levels,
+ &self.effective_visibilities,
);
- self.update(item.def_id.def_id, impl_level)
+ self.update(item.owner_id.def_id, impl_level)
}
- _ => self.get(item.def_id.def_id),
+ _ => self.get(item.owner_id.def_id),
};
// Update levels of nested things.
hir::ItemKind::Impl(ref impl_) => {
for impl_item_ref in impl_.items {
if impl_.of_trait.is_some()
- || self.tcx.visibility(impl_item_ref.id.def_id).is_public()
+ || self.tcx.visibility(impl_item_ref.id.owner_id).is_public()
{
- self.update(impl_item_ref.id.def_id.def_id, item_level);
+ self.update(impl_item_ref.id.owner_id.def_id, item_level);
}
}
}
hir::ItemKind::Trait(.., trait_item_refs) => {
for trait_item_ref in trait_item_refs {
- self.update(trait_item_ref.id.def_id.def_id, item_level);
+ self.update(trait_item_ref.id.owner_id.def_id, item_level);
}
}
hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
}
}
hir::ItemKind::Macro(ref macro_def, _) => {
- self.update_reachability_from_macro(item.def_id.def_id, macro_def);
+ self.update_reachability_from_macro(item.owner_id.def_id, macro_def);
}
hir::ItemKind::ForeignMod { items, .. } => {
for foreign_item in items {
- if self.tcx.visibility(foreign_item.id.def_id).is_public() {
- self.update(foreign_item.id.def_id.def_id, item_level);
+ if self.tcx.visibility(foreign_item.id.owner_id).is_public() {
+ self.update(foreign_item.id.owner_id.def_id, item_level);
}
}
}
hir::ItemKind::Macro(..) | hir::ItemKind::ExternCrate(..) => {}
// All nested items are checked by `visit_item`.
hir::ItemKind::Mod(..) => {}
- // Handled in the access level of in rustc_resolve
+ // Handled in `rustc_resolve`.
hir::ItemKind::Use(..) => {}
// The interface is empty.
hir::ItemKind::GlobalAsm(..) => {}
// FIXME: This is some serious pessimization intended to workaround deficiencies
// in the reachability pass (`middle/reachable.rs`). Types are marked as link-time
// reachable if they are returned via `impl Trait`, even from private functions.
- let exist_level =
- cmp::max(item_level, Some(AccessLevel::ReachableFromImplTrait));
- self.reach(item.def_id.def_id, exist_level).generics().predicates().ty();
+ let exist_level = cmp::max(item_level, Some(Level::ReachableThroughImplTrait));
+ self.reach(item.owner_id.def_id, exist_level).generics().predicates().ty();
}
}
// Visit everything.
| hir::ItemKind::Fn(..)
| hir::ItemKind::TyAlias(..) => {
if item_level.is_some() {
- self.reach(item.def_id.def_id, item_level).generics().predicates().ty();
+ self.reach(item.owner_id.def_id, item_level).generics().predicates().ty();
}
}
hir::ItemKind::Trait(.., trait_item_refs) => {
if item_level.is_some() {
- self.reach(item.def_id.def_id, item_level).generics().predicates();
+ self.reach(item.owner_id.def_id, item_level).generics().predicates();
for trait_item_ref in trait_item_refs {
let tcx = self.tcx;
- let mut reach = self.reach(trait_item_ref.id.def_id.def_id, item_level);
+ let mut reach = self.reach(trait_item_ref.id.owner_id.def_id, item_level);
reach.generics().predicates();
if trait_item_ref.kind == AssocItemKind::Type
- && !tcx.impl_defaultness(trait_item_ref.id.def_id).has_value()
+ && !tcx.impl_defaultness(trait_item_ref.id.owner_id).has_value()
{
// No type to visit.
} else {
}
hir::ItemKind::TraitAlias(..) => {
if item_level.is_some() {
- self.reach(item.def_id.def_id, item_level).generics().predicates();
+ self.reach(item.owner_id.def_id, item_level).generics().predicates();
}
}
// Visit everything except for private impl items.
hir::ItemKind::Impl(ref impl_) => {
if item_level.is_some() {
- self.reach(item.def_id.def_id, item_level)
+ self.reach(item.owner_id.def_id, item_level)
.generics()
.predicates()
.ty()
.trait_ref();
for impl_item_ref in impl_.items {
- let impl_item_level = self.get(impl_item_ref.id.def_id.def_id);
+ let impl_item_level = self.get(impl_item_ref.id.owner_id.def_id);
if impl_item_level.is_some() {
- self.reach(impl_item_ref.id.def_id.def_id, impl_item_level)
+ self.reach(impl_item_ref.id.owner_id.def_id, impl_item_level)
.generics()
.predicates()
.ty();
// Visit everything, but enum variants have their own levels.
hir::ItemKind::Enum(ref def, _) => {
if item_level.is_some() {
- self.reach(item.def_id.def_id, item_level).generics().predicates();
+ self.reach(item.owner_id.def_id, item_level).generics().predicates();
}
for variant in def.variants {
let variant_level = self.get(self.tcx.hir().local_def_id(variant.id));
}
// Corner case: if the variant is reachable, but its
// enum is not, make the enum reachable as well.
- self.reach(item.def_id.def_id, variant_level).ty();
+ self.reach(item.owner_id.def_id, variant_level).ty();
}
if let Some(hir_id) = variant.data.ctor_hir_id() {
let ctor_def_id = self.tcx.hir().local_def_id(hir_id);
let ctor_level = self.get(ctor_def_id);
if ctor_level.is_some() {
- self.reach(item.def_id.def_id, ctor_level).ty();
+ self.reach(item.owner_id.def_id, ctor_level).ty();
}
}
}
// Visit everything, but foreign items have their own levels.
hir::ItemKind::ForeignMod { items, .. } => {
for foreign_item in items {
- let foreign_item_level = self.get(foreign_item.id.def_id.def_id);
+ let foreign_item_level = self.get(foreign_item.id.owner_id.def_id);
if foreign_item_level.is_some() {
- self.reach(foreign_item.id.def_id.def_id, foreign_item_level)
+ self.reach(foreign_item.id.owner_id.def_id, foreign_item_level)
.generics()
.predicates()
.ty();
// Visit everything except for private fields.
hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
if item_level.is_some() {
- self.reach(item.def_id.def_id, item_level).generics().predicates();
+ self.reach(item.owner_id.def_id, item_level).generics().predicates();
for field in struct_def.fields() {
let def_id = self.tcx.hir().local_def_id(field.hir_id);
let field_level = self.get(def_id);
let ctor_def_id = self.tcx.hir().local_def_id(hir_id);
let ctor_level = self.get(ctor_def_id);
if ctor_level.is_some() {
- self.reach(item.def_id.def_id, ctor_level).ty();
+ self.reach(item.owner_id.def_id, ctor_level).ty();
}
}
}
_descr: &dyn fmt::Display,
) -> ControlFlow<Self::BreakTy> {
if let Some(def_id) = def_id.as_local() {
- if let (ty::Visibility::Public, _) | (_, Some(AccessLevel::ReachableFromImplTrait)) =
- (self.tcx().visibility(def_id.to_def_id()), self.access_level)
+ if let (ty::Visibility::Public, _) | (_, Some(Level::ReachableThroughImplTrait)) =
+ (self.tcx().visibility(def_id.to_def_id()), self.level)
{
- self.ev.update(def_id, self.access_level);
+ self.ev.update(def_id, self.level);
}
}
ControlFlow::CONTINUE
}
////////////////////////////////////////////////////////////////////////////////
-/// Visitor, used for AccessLevels table checking
+/// Visitor, used for EffectiveVisibilities table checking
////////////////////////////////////////////////////////////////////////////////
pub struct TestReachabilityVisitor<'tcx, 'a> {
tcx: TyCtxt<'tcx>,
- access_levels: &'a AccessLevels,
+ effective_visibilities: &'a EffectiveVisibilities,
}
impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> {
- fn access_level_diagnostic(&mut self, def_id: LocalDefId) {
+ fn effective_visibility_diagnostic(&mut self, def_id: LocalDefId) {
if self.tcx.has_attr(def_id.to_def_id(), sym::rustc_effective_visibility) {
let mut error_msg = String::new();
let span = self.tcx.def_span(def_id.to_def_id());
- if let Some(effective_vis) = self.access_levels.get_effective_vis(def_id) {
- for level in AccessLevel::all_levels() {
- let vis_str = match effective_vis.get(level) {
+ if let Some(effective_vis) = self.effective_visibilities.effective_vis(def_id) {
+ for level in Level::all_levels() {
+ let vis_str = match effective_vis.at_level(level) {
ty::Visibility::Restricted(restricted_id) => {
if restricted_id.is_top_level_module() {
"pub(crate)".to_string()
}
ty::Visibility::Public => "pub".to_string(),
};
- if level != AccessLevel::Public {
+ if level != Level::Direct {
error_msg.push_str(", ");
}
error_msg.push_str(&format!("{:?}: {}", level, vis_str));
impl<'tcx, 'a> Visitor<'tcx> for TestReachabilityVisitor<'tcx, 'a> {
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
- self.access_level_diagnostic(item.def_id.def_id);
+ self.effective_visibility_diagnostic(item.owner_id.def_id);
match item.kind {
hir::ItemKind::Enum(ref def, _) => {
for variant in def.variants.iter() {
let variant_id = self.tcx.hir().local_def_id(variant.id);
- self.access_level_diagnostic(variant_id);
+ self.effective_visibility_diagnostic(variant_id);
+ if let Some(ctor_hir_id) = variant.data.ctor_hir_id() {
+ let ctor_def_id = self.tcx.hir().local_def_id(ctor_hir_id);
+ self.effective_visibility_diagnostic(ctor_def_id);
+ }
for field in variant.data.fields() {
let def_id = self.tcx.hir().local_def_id(field.hir_id);
- self.access_level_diagnostic(def_id);
+ self.effective_visibility_diagnostic(def_id);
}
}
}
hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
+ if let Some(ctor_hir_id) = def.ctor_hir_id() {
+ let ctor_def_id = self.tcx.hir().local_def_id(ctor_hir_id);
+ self.effective_visibility_diagnostic(ctor_def_id);
+ }
for field in def.fields() {
let def_id = self.tcx.hir().local_def_id(field.hir_id);
- self.access_level_diagnostic(def_id);
+ self.effective_visibility_diagnostic(def_id);
}
}
_ => {}
}
fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem<'tcx>) {
- self.access_level_diagnostic(item.def_id.def_id);
+ self.effective_visibility_diagnostic(item.owner_id.def_id);
}
fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem<'tcx>) {
- self.access_level_diagnostic(item.def_id.def_id);
+ self.effective_visibility_diagnostic(item.owner_id.def_id);
}
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
- self.access_level_diagnostic(item.def_id.def_id);
+ self.effective_visibility_diagnostic(item.owner_id.def_id);
}
}
fn visit_mod(&mut self, _m: &'tcx hir::Mod<'tcx>, _s: Span, _n: hir::HirId) {
// Don't visit nested modules, since we run a separate visitor walk
- // for each module in `privacy_access_levels`
+ // for each module in `effective_visibilities`
}
fn visit_nested_body(&mut self, body: hir::BodyId) {
}
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
- let orig_current_item = mem::replace(&mut self.current_item, item.def_id.def_id);
+ let orig_current_item = mem::replace(&mut self.current_item, item.owner_id.def_id);
intravisit::walk_item(self, item);
self.current_item = orig_current_item;
}
fn visit_mod(&mut self, _m: &'tcx hir::Mod<'tcx>, _s: Span, _n: hir::HirId) {
// Don't visit nested modules, since we run a separate visitor walk
- // for each module in `privacy_access_levels`
+ // for each module in `effective_visibilities`
}
fn visit_nested_body(&mut self, body: hir::BodyId) {
// Check types in item interfaces.
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
- let orig_current_item = mem::replace(&mut self.current_item, item.def_id.def_id);
+ let orig_current_item = mem::replace(&mut self.current_item, item.owner_id.def_id);
let old_maybe_typeck_results = self.maybe_typeck_results.take();
intravisit::walk_item(self, item);
self.maybe_typeck_results = old_maybe_typeck_results;
struct ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
- access_levels: &'a AccessLevels,
+ effective_visibilities: &'a EffectiveVisibilities,
in_variant: bool,
// Set of errors produced by this obsolete visitor.
old_error_set: HirIdSet,
fn trait_is_public(&self, trait_id: LocalDefId) -> bool {
// FIXME: this would preferably be using `exported_items`, but all
// traits are exported currently (see `EmbargoVisitor.exported_trait`).
- self.access_levels.is_public(trait_id)
+ self.effective_visibilities.is_directly_public(trait_id)
}
fn check_generic_bound(&mut self, bound: &hir::GenericBound<'_>) {
}
fn item_is_public(&self, def_id: LocalDefId) -> bool {
- self.access_levels.is_reachable(def_id) || self.tcx.visibility(def_id).is_public()
+ self.effective_visibilities.is_reachable(def_id) || self.tcx.visibility(def_id).is_public()
}
}
hir::ItemKind::ForeignMod { .. } => {}
hir::ItemKind::Trait(.., bounds, _) => {
- if !self.trait_is_public(item.def_id.def_id) {
+ if !self.trait_is_public(item.owner_id.def_id) {
return;
}
|| impl_.items.iter().any(|impl_item_ref| {
let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
match impl_item.kind {
- hir::ImplItemKind::Const(..) | hir::ImplItemKind::Fn(..) => {
- self.access_levels.is_reachable(impl_item_ref.id.def_id.def_id)
- }
+ hir::ImplItemKind::Const(..) | hir::ImplItemKind::Fn(..) => self
+ .effective_visibilities
+ .is_reachable(impl_item_ref.id.owner_id.def_id),
hir::ImplItemKind::Type(_) => false,
}
});
let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
match impl_item.kind {
hir::ImplItemKind::Const(..) | hir::ImplItemKind::Fn(..)
- if self.item_is_public(impl_item.def_id.def_id) =>
+ if self.item_is_public(impl_item.owner_id.def_id) =>
{
intravisit::walk_impl_item(self, impl_item)
}
// methods will be visible as `Public::foo`.
let mut found_pub_static = false;
for impl_item_ref in impl_.items {
- if self.access_levels.is_reachable(impl_item_ref.id.def_id.def_id)
- || self.tcx.visibility(impl_item_ref.id.def_id).is_public()
+ if self
+ .effective_visibilities
+ .is_reachable(impl_item_ref.id.owner_id.def_id)
+ || self.tcx.visibility(impl_item_ref.id.owner_id).is_public()
{
let impl_item = self.tcx.hir().impl_item(impl_item_ref.id);
match impl_item_ref.kind {
hir::ItemKind::TyAlias(..) => return,
// Not at all public, so we don't care.
- _ if !self.item_is_public(item.def_id.def_id) => {
+ _ if !self.item_is_public(item.owner_id.def_id) => {
return;
}
}
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
- if self.access_levels.is_reachable(item.def_id.def_id) {
+ if self.effective_visibilities.is_reachable(item.owner_id.def_id) {
intravisit::walk_foreign_item(self, item)
}
}
}
fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) {
- if self.access_levels.is_reachable(self.tcx.hir().local_def_id(v.id)) {
+ if self.effective_visibilities.is_reachable(self.tcx.hir().local_def_id(v.id)) {
self.in_variant = true;
intravisit::walk_variant(self, v);
self.in_variant = false;
pub fn check_item(&mut self, id: ItemId) {
let tcx = self.tcx;
- let def_id = id.def_id.def_id;
+ let def_id = id.owner_id.def_id;
let item_visibility = tcx.local_visibility(def_id);
let def_kind = tcx.def_kind(def_id);
DefKind::Trait => {
let item = tcx.hir().item(id);
if let hir::ItemKind::Trait(.., trait_item_refs) = item.kind {
- self.check(item.def_id.def_id, item_visibility).generics().predicates();
+ self.check(item.owner_id.def_id, item_visibility).generics().predicates();
for trait_item_ref in trait_item_refs {
self.check_assoc_item(
- trait_item_ref.id.def_id.def_id,
+ trait_item_ref.id.owner_id.def_id,
trait_item_ref.kind,
item_visibility,
);
if let AssocItemKind::Type = trait_item_ref.kind {
- self.check(trait_item_ref.id.def_id.def_id, item_visibility).bounds();
+ self.check(trait_item_ref.id.owner_id.def_id, item_visibility).bounds();
}
}
}
DefKind::Enum => {
let item = tcx.hir().item(id);
if let hir::ItemKind::Enum(ref def, _) = item.kind {
- self.check(item.def_id.def_id, item_visibility).generics().predicates();
+ self.check(item.owner_id.def_id, item_visibility).generics().predicates();
for variant in def.variants {
for field in variant.data.fields() {
let item = tcx.hir().item(id);
if let hir::ItemKind::ForeignMod { items, .. } = item.kind {
for foreign_item in items {
- let vis = tcx.local_visibility(foreign_item.id.def_id.def_id);
- self.check(foreign_item.id.def_id.def_id, vis).generics().predicates().ty();
+ let vis = tcx.local_visibility(foreign_item.id.owner_id.def_id);
+ self.check(foreign_item.id.owner_id.def_id, vis)
+ .generics()
+ .predicates()
+ .ty();
}
}
}
if let hir::ItemKind::Struct(ref struct_def, _)
| hir::ItemKind::Union(ref struct_def, _) = item.kind
{
- self.check(item.def_id.def_id, item_visibility).generics().predicates();
+ self.check(item.owner_id.def_id, item_visibility).generics().predicates();
for field in struct_def.fields() {
let def_id = tcx.hir().local_def_id(field.hir_id);
let item = tcx.hir().item(id);
if let hir::ItemKind::Impl(ref impl_) = item.kind {
let impl_vis =
- ty::Visibility::of_impl(item.def_id.def_id, tcx, &Default::default());
+ ty::Visibility::of_impl(item.owner_id.def_id, tcx, &Default::default());
// check that private components do not appear in the generics or predicates of inherent impls
// this check is intentionally NOT performed for impls of traits, per #90586
if impl_.of_trait.is_none() {
- self.check(item.def_id.def_id, impl_vis).generics().predicates();
+ self.check(item.owner_id.def_id, impl_vis).generics().predicates();
}
for impl_item_ref in impl_.items {
let impl_item_vis = if impl_.of_trait.is_none() {
- min(tcx.local_visibility(impl_item_ref.id.def_id.def_id), impl_vis, tcx)
+ min(
+ tcx.local_visibility(impl_item_ref.id.owner_id.def_id),
+ impl_vis,
+ tcx,
+ )
} else {
impl_vis
};
self.check_assoc_item(
- impl_item_ref.id.def_id.def_id,
+ impl_item_ref.id.owner_id.def_id,
impl_item_ref.kind,
impl_item_vis,
);
pub fn provide(providers: &mut Providers) {
*providers = Providers {
visibility,
- privacy_access_levels,
+ effective_visibilities,
check_private_in_public,
check_mod_privacy,
..*providers
intravisit::walk_mod(&mut visitor, module, hir_id);
}
-fn privacy_access_levels(tcx: TyCtxt<'_>, (): ()) -> &AccessLevels {
+fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities {
// Build up a set of all exported items in the AST. This is a set of all
// items which are reachable from external crates based on visibility.
let mut visitor = EmbargoVisitor {
tcx,
- access_levels: tcx.resolutions(()).access_levels.clone(),
+ effective_visibilities: tcx.resolutions(()).effective_visibilities.clone(),
macro_reachable: Default::default(),
- prev_level: Some(AccessLevel::Public),
+ prev_level: Some(Level::Direct),
changed: false,
};
+ visitor.effective_visibilities.check_invariants(tcx, true);
loop {
tcx.hir().walk_toplevel_module(&mut visitor);
if visitor.changed {
break;
}
}
+ visitor.effective_visibilities.check_invariants(tcx, false);
- let mut check_visitor = TestReachabilityVisitor { tcx, access_levels: &visitor.access_levels };
+ let mut check_visitor =
+ TestReachabilityVisitor { tcx, effective_visibilities: &visitor.effective_visibilities };
tcx.hir().visit_all_item_likes_in_crate(&mut check_visitor);
- tcx.arena.alloc(visitor.access_levels)
+ tcx.arena.alloc(visitor.effective_visibilities)
}
fn check_private_in_public(tcx: TyCtxt<'_>, (): ()) {
- let access_levels = tcx.privacy_access_levels(());
+ let effective_visibilities = tcx.effective_visibilities(());
let mut visitor = ObsoleteVisiblePrivateTypesVisitor {
tcx,
- access_levels,
+ effective_visibilities,
in_variant: false,
old_error_set: Default::default(),
};
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
-thin-vec = "0.2.8"
+thin-vec = "0.2.9"
tracing = "0.1"
[features]
use keys::Key;
pub use rustc_query_system::query::QueryConfig;
-pub(crate) use rustc_query_system::query::{QueryDescription, QueryVTable};
+pub(crate) use rustc_query_system::query::QueryVTable;
mod on_disk_cache;
pub use on_disk_cache::OnDiskCache;
use crate::QueryCtxt;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
+use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, RwLock};
use rustc_data_structures::unhash::UnhashMap;
+use rustc_data_structures::unord::UnordSet;
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, StableCrateId, LOCAL_CRATE};
use rustc_hir::definitions::DefPathHash;
use rustc_index::vec::{Idx, IndexVec};
}
}
-impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx FxHashSet<LocalDefId> {
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx UnordSet<LocalDefId> {
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
RefDecodable::decode(d)
}
query_result_index: &mut EncodedDepNodeIndex,
) where
CTX: QueryContext + 'tcx,
- Q: super::QueryDescription<CTX>,
+ Q: super::QueryConfig<CTX>,
Q::Value: Encodable<CacheEncoder<'a, 'tcx>>,
{
let _timer = tcx
use rustc_query_system::dep_graph::{DepNodeParams, HasDepContext};
use rustc_query_system::ich::StableHashingContext;
use rustc_query_system::query::{
- force_query, QueryConfig, QueryContext, QueryDescription, QueryJobId, QueryMap,
- QuerySideEffects, QueryStackFrame,
+ force_query, QueryConfig, QueryContext, QueryJobId, QueryMap, QuerySideEffects, QueryStackFrame,
};
use rustc_query_system::{LayoutOfDepth, QueryOverflow, Value};
use rustc_serialize::Decodable;
fn try_load_from_on_disk_cache<'tcx, Q>(tcx: TyCtxt<'tcx>, dep_node: DepNode)
where
- Q: QueryDescription<QueryCtxt<'tcx>>,
+ Q: QueryConfig<QueryCtxt<'tcx>>,
Q::Key: DepNodeParams<TyCtxt<'tcx>>,
{
debug_assert!(tcx.dep_graph.is_green(&dep_node));
fn force_from_dep_node<'tcx, Q>(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> bool
where
- Q: QueryDescription<QueryCtxt<'tcx>>,
+ Q: QueryConfig<QueryCtxt<'tcx>>,
Q::Key: DepNodeParams<TyCtxt<'tcx>>,
Q::Value: Value<TyCtxt<'tcx>>,
{
}
}
-pub(crate) fn query_callback<'tcx, Q: QueryConfig>(
- is_anon: bool,
- is_eval_always: bool,
-) -> DepKindStruct<'tcx>
+pub(crate) fn query_callback<'tcx, Q>(is_anon: bool, is_eval_always: bool) -> DepKindStruct<'tcx>
where
- Q: QueryDescription<QueryCtxt<'tcx>>,
+ Q: QueryConfig<QueryCtxt<'tcx>>,
Q::Key: DepNodeParams<TyCtxt<'tcx>>,
{
let fingerprint_style = Q::Key::fingerprint_style();
})*
}
- $(impl<'tcx> QueryConfig for queries::$name<'tcx> {
+ $(impl<'tcx> QueryConfig<QueryCtxt<'tcx>> for queries::$name<'tcx> {
type Key = query_keys::$name<'tcx>;
type Value = query_values::$name<'tcx>;
type Stored = query_stored::$name<'tcx>;
const NAME: &'static str = stringify!($name);
- }
- impl<'tcx> QueryDescription<QueryCtxt<'tcx>> for queries::$name<'tcx> {
#[inline]
fn cache_on_disk(tcx: TyCtxt<'tcx>, key: &Self::Key) -> bool {
::rustc_middle::query::cached::$name(tcx, key)
local_providers: Box<Providers>,
extern_providers: Box<ExternProviders>,
query_structs: Vec<$crate::plumbing::QueryStruct<'tcx>>,
-
pub on_disk_cache: Option<OnDiskCache<'tcx>>,
-
jobs: AtomicU64,
- $($(#[$attr])* $name: QueryState<<queries::$name<'tcx> as QueryConfig>::Key>,)*
+ $(
+ $(#[$attr])*
+ $name: QueryState<
+ <queries::$name<'tcx> as QueryConfig<QueryCtxt<'tcx>>>::Key
+ >,
+ )*
}
impl<'tcx> Queries<'tcx> {
&'tcx self,
tcx: TyCtxt<'tcx>,
span: Span,
- key: <queries::$name<'tcx> as QueryConfig>::Key,
+ key: <queries::$name<'tcx> as QueryConfig<QueryCtxt<'tcx>>>::Key,
mode: QueryMode,
) -> Option<query_stored::$name<'tcx>> {
let qcx = QueryCtxt { tcx, queries: self };
}
}
-struct QueryKeyStringBuilder<'p, 'c, 'tcx> {
+struct QueryKeyStringBuilder<'p, 'tcx> {
profiler: &'p SelfProfiler,
tcx: TyCtxt<'tcx>,
- string_cache: &'c mut QueryKeyStringCache,
+ string_cache: &'p mut QueryKeyStringCache,
}
-impl<'p, 'c, 'tcx> QueryKeyStringBuilder<'p, 'c, 'tcx> {
+impl<'p, 'tcx> QueryKeyStringBuilder<'p, 'tcx> {
fn new(
profiler: &'p SelfProfiler,
tcx: TyCtxt<'tcx>,
- string_cache: &'c mut QueryKeyStringCache,
- ) -> QueryKeyStringBuilder<'p, 'c, 'tcx> {
+ string_cache: &'p mut QueryKeyStringCache,
+ ) -> QueryKeyStringBuilder<'p, 'tcx> {
QueryKeyStringBuilder { profiler, tcx, string_cache }
}
}
trait IntoSelfProfilingString {
- fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId;
+ fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId;
}
// The default implementation of `IntoSelfProfilingString` just uses `Debug`
impl<T: Debug> IntoSelfProfilingString for T {
default fn to_self_profile_string(
&self,
- builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
+ builder: &mut QueryKeyStringBuilder<'_, '_>,
) -> StringId {
let s = format!("{:?}", self);
builder.profiler.alloc_string(&s[..])
}
impl<T: SpecIntoSelfProfilingString> IntoSelfProfilingString for T {
- fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId {
+ fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId {
self.spec_to_self_profile_string(builder)
}
}
#[rustc_specialization_trait]
trait SpecIntoSelfProfilingString: Debug {
- fn spec_to_self_profile_string(
- &self,
- builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
- ) -> StringId;
+ fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId;
}
impl SpecIntoSelfProfilingString for DefId {
- fn spec_to_self_profile_string(
- &self,
- builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
- ) -> StringId {
+ fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId {
builder.def_id_to_string_id(*self)
}
}
impl SpecIntoSelfProfilingString for CrateNum {
- fn spec_to_self_profile_string(
- &self,
- builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
- ) -> StringId {
+ fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId {
builder.def_id_to_string_id(self.as_def_id())
}
}
impl SpecIntoSelfProfilingString for DefIndex {
- fn spec_to_self_profile_string(
- &self,
- builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
- ) -> StringId {
+ fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId {
builder.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: *self })
}
}
impl SpecIntoSelfProfilingString for LocalDefId {
- fn spec_to_self_profile_string(
- &self,
- builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
- ) -> StringId {
+ fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId {
builder.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: self.local_def_index })
}
}
impl<T: SpecIntoSelfProfilingString> SpecIntoSelfProfilingString for WithOptConstParam<T> {
- fn spec_to_self_profile_string(
- &self,
- builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
- ) -> StringId {
+ fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId {
// We print `WithOptConstParam` values as tuples to make them shorter
// and more readable, without losing information:
//
T0: SpecIntoSelfProfilingString,
T1: SpecIntoSelfProfilingString,
{
- fn spec_to_self_profile_string(
- &self,
- builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
- ) -> StringId {
+ fn spec_to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_>) -> StringId {
let val0 = self.0.to_self_profile_string(builder);
let val1 = self.1.to_self_profile_string(builder);
rustc_target = { path = "../rustc_target" }
rustc_type_ir = { path = "../rustc_type_ir" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
-thin-vec = "0.2.8"
+thin-vec = "0.2.9"
tracing = "0.1"
[features]
}
impl<Key: Eq + Hash, Value: Clone> Cache<Key, Value> {
- pub fn get<CTX: DepContext>(&self, key: &Key, tcx: CTX) -> Option<Value> {
+ pub fn get<Tcx: DepContext>(&self, key: &Key, tcx: Tcx) -> Option<Value> {
Some(self.hashmap.borrow().get(key)?.get(tcx))
}
WithDepNode { dep_node, cached_value }
}
- pub fn get<CTX: DepContext>(&self, tcx: CTX) -> T {
+ pub fn get<Tcx: DepContext>(&self, tcx: Tcx) -> T {
tcx.dep_graph().read_index(self.dep_node);
self.cached_value.clone()
}
/// Creates a new, parameterless DepNode. This method will assert
/// that the DepNode corresponding to the given DepKind actually
/// does not require any parameters.
- pub fn new_no_params<Ctxt>(tcx: Ctxt, kind: K) -> DepNode<K>
+ pub fn new_no_params<Tcx>(tcx: Tcx, kind: K) -> DepNode<K>
where
- Ctxt: super::DepContext<DepKind = K>,
+ Tcx: super::DepContext<DepKind = K>,
{
debug_assert_eq!(tcx.fingerprint_style(kind), FingerprintStyle::Unit);
DepNode { kind, hash: Fingerprint::ZERO.into() }
}
- pub fn construct<Ctxt, Key>(tcx: Ctxt, kind: K, arg: &Key) -> DepNode<K>
+ pub fn construct<Tcx, Key>(tcx: Tcx, kind: K, arg: &Key) -> DepNode<K>
where
- Ctxt: super::DepContext<DepKind = K>,
- Key: DepNodeParams<Ctxt>,
+ Tcx: super::DepContext<DepKind = K>,
+ Key: DepNodeParams<Tcx>,
{
let hash = arg.to_fingerprint(tcx);
let dep_node = DepNode { kind, hash: hash.into() };
/// Construct a DepNode from the given DepKind and DefPathHash. This
/// method will assert that the given DepKind actually requires a
/// single DefId/DefPathHash parameter.
- pub fn from_def_path_hash<Ctxt>(tcx: Ctxt, def_path_hash: DefPathHash, kind: K) -> Self
+ pub fn from_def_path_hash<Tcx>(tcx: Tcx, def_path_hash: DefPathHash, kind: K) -> Self
where
- Ctxt: super::DepContext<DepKind = K>,
+ Tcx: super::DepContext<DepKind = K>,
{
debug_assert!(tcx.fingerprint_style(kind) == FingerprintStyle::DefPathHash);
DepNode { kind, hash: def_path_hash.0.into() }
}
}
-pub trait DepNodeParams<Ctxt: DepContext>: fmt::Debug + Sized {
+pub trait DepNodeParams<Tcx: DepContext>: fmt::Debug + Sized {
fn fingerprint_style() -> FingerprintStyle;
/// This method turns the parameters of a DepNodeConstructor into an opaque
/// Fingerprint to be used in DepNode.
/// Not all DepNodeParams support being turned into a Fingerprint (they
/// don't need to if the corresponding DepNode is anonymous).
- fn to_fingerprint(&self, _: Ctxt) -> Fingerprint {
+ fn to_fingerprint(&self, _: Tcx) -> Fingerprint {
panic!("Not implemented. Accidentally called on anonymous node?")
}
- fn to_debug_str(&self, _: Ctxt) -> String {
+ fn to_debug_str(&self, _: Tcx) -> String {
format!("{:?}", self)
}
/// `fingerprint_style()` is not `FingerprintStyle::Opaque`.
/// It is always valid to return `None` here, in which case incremental
/// compilation will treat the query as having changed instead of forcing it.
- fn recover(tcx: Ctxt, dep_node: &DepNode<Ctxt::DepKind>) -> Option<Self>;
+ fn recover(tcx: Tcx, dep_node: &DepNode<Tcx::DepKind>) -> Option<Self>;
}
-impl<Ctxt: DepContext, T> DepNodeParams<Ctxt> for T
+impl<Tcx: DepContext, T> DepNodeParams<Tcx> for T
where
T: for<'a> HashStable<StableHashingContext<'a>> + fmt::Debug,
{
}
#[inline(always)]
- default fn to_fingerprint(&self, tcx: Ctxt) -> Fingerprint {
+ default fn to_fingerprint(&self, tcx: Tcx) -> Fingerprint {
tcx.with_stable_hashing_context(|mut hcx| {
let mut hasher = StableHasher::new();
self.hash_stable(&mut hcx, &mut hasher);
}
#[inline(always)]
- default fn to_debug_str(&self, _: Ctxt) -> String {
+ default fn to_debug_str(&self, _: Tcx) -> String {
format!("{:?}", *self)
}
#[inline(always)]
- default fn recover(_: Ctxt, _: &DepNode<Ctxt::DepKind>) -> Option<Self> {
+ default fn recover(_: Tcx, _: &DepNode<Tcx::DepKind>) -> Option<Self> {
None
}
}
/// Information is retrieved by indexing the `DEP_KINDS` array using the integer value
/// of the `DepKind`. Overall, this allows to implement `DepContext` using this manual
/// jump table instead of large matches.
-pub struct DepKindStruct<CTX: DepContext> {
+pub struct DepKindStruct<Tcx: DepContext> {
/// Anonymous queries cannot be replayed from one compiler invocation to the next.
/// When their result is needed, it is recomputed. They are useful for fine-grained
/// dependency tracking, and caching within one compiler invocation.
/// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode`
/// is actually a `DefPathHash`, and can therefore just look up the corresponding
/// `DefId` in `tcx.def_path_hash_to_def_id`.
- pub force_from_dep_node: Option<fn(tcx: CTX, dep_node: DepNode<CTX::DepKind>) -> bool>,
+ pub force_from_dep_node: Option<fn(tcx: Tcx, dep_node: DepNode<Tcx::DepKind>) -> bool>,
/// Invoke a query to put the on-disk cached value in memory.
- pub try_load_from_on_disk_cache: Option<fn(CTX, DepNode<CTX::DepKind>)>,
+ pub try_load_from_on_disk_cache: Option<fn(Tcx, DepNode<Tcx::DepKind>)>,
}
/// A "work product" corresponds to a `.o` (or other) file that we
/// Executes something within an "anonymous" task, that is, a task the
/// `DepNode` of which is determined by the list of inputs it read from.
- pub fn with_anon_task<Ctxt: DepContext<DepKind = K>, OP, R>(
+ pub fn with_anon_task<Tcx: DepContext<DepKind = K>, OP, R>(
&self,
- cx: Ctxt,
+ cx: Tcx,
dep_kind: K,
op: OP,
) -> (R, DepNodeIndex)
/// A node will have an index, when it's already been marked green, or when we can mark it
/// green. This function will mark the current task as a reader of the specified node, when
/// a node index can be found for that node.
- pub fn try_mark_green<Ctxt: QueryContext<DepKind = K>>(
+ pub fn try_mark_green<Qcx: QueryContext<DepKind = K>>(
&self,
- tcx: Ctxt,
+ qcx: Qcx,
dep_node: &DepNode<K>,
) -> Option<(SerializedDepNodeIndex, DepNodeIndex)> {
- debug_assert!(!tcx.dep_context().is_eval_always(dep_node.kind));
+ debug_assert!(!qcx.dep_context().is_eval_always(dep_node.kind));
// Return None if the dep graph is disabled
let data = self.data.as_ref()?;
// in the previous compilation session too, so we can try to
// mark it as green by recursively marking all of its
// dependencies green.
- self.try_mark_previous_green(tcx, data, prev_index, &dep_node)
+ self.try_mark_previous_green(qcx, data, prev_index, &dep_node)
.map(|dep_node_index| (prev_index, dep_node_index))
}
}
}
- fn try_mark_parent_green<Ctxt: QueryContext<DepKind = K>>(
+ #[instrument(skip(self, qcx, data, parent_dep_node_index), level = "debug")]
+ fn try_mark_parent_green<Qcx: QueryContext<DepKind = K>>(
&self,
- tcx: Ctxt,
+ qcx: Qcx,
data: &DepGraphData<K>,
parent_dep_node_index: SerializedDepNodeIndex,
dep_node: &DepNode<K>,
// This dependency has been marked as green before, we are
// still fine and can continue with checking the other
// dependencies.
- debug!(
- "try_mark_previous_green({:?}) --- found dependency {:?} to \
- be immediately green",
- dep_node, dep_dep_node,
- );
+ debug!("dependency {dep_dep_node:?} was immediately green");
return Some(());
}
Some(DepNodeColor::Red) => {
// compared to the previous compilation session. We cannot
// mark the DepNode as green and also don't need to bother
// with checking any of the other dependencies.
- debug!(
- "try_mark_previous_green({:?}) - END - dependency {:?} was immediately red",
- dep_node, dep_dep_node,
- );
+ debug!("dependency {dep_dep_node:?} was immediately red");
return None;
}
None => {}
// We don't know the state of this dependency. If it isn't
// an eval_always node, let's try to mark it green recursively.
- if !tcx.dep_context().is_eval_always(dep_dep_node.kind) {
+ if !qcx.dep_context().is_eval_always(dep_dep_node.kind) {
debug!(
- "try_mark_previous_green({:?}) --- state of dependency {:?} ({}) \
- is unknown, trying to mark it green",
- dep_node, dep_dep_node, dep_dep_node.hash,
+ "state of dependency {:?} ({}) is unknown, trying to mark it green",
+ dep_dep_node, dep_dep_node.hash,
);
let node_index =
- self.try_mark_previous_green(tcx, data, parent_dep_node_index, dep_dep_node);
+ self.try_mark_previous_green(qcx, data, parent_dep_node_index, dep_dep_node);
+
if node_index.is_some() {
- debug!(
- "try_mark_previous_green({:?}) --- managed to MARK dependency {:?} as green",
- dep_node, dep_dep_node
- );
+ debug!("managed to MARK dependency {dep_dep_node:?} as green",);
return Some(());
}
}
// We failed to mark it green, so we try to force the query.
- debug!(
- "try_mark_previous_green({:?}) --- trying to force dependency {:?}",
- dep_node, dep_dep_node
- );
- if !tcx.dep_context().try_force_from_dep_node(*dep_dep_node) {
+ debug!("trying to force dependency {dep_dep_node:?}");
+ if !qcx.dep_context().try_force_from_dep_node(*dep_dep_node) {
// The DepNode could not be forced.
- debug!(
- "try_mark_previous_green({:?}) - END - dependency {:?} could not be forced",
- dep_node, dep_dep_node
- );
+ debug!("dependency {dep_dep_node:?} could not be forced");
return None;
}
match dep_dep_node_color {
Some(DepNodeColor::Green(_)) => {
- debug!(
- "try_mark_previous_green({:?}) --- managed to FORCE dependency {:?} to green",
- dep_node, dep_dep_node
- );
+ debug!("managed to FORCE dependency {dep_dep_node:?} to green");
return Some(());
}
Some(DepNodeColor::Red) => {
- debug!(
- "try_mark_previous_green({:?}) - END - dependency {:?} was red after forcing",
- dep_node, dep_dep_node
- );
+ debug!("dependency {dep_dep_node:?} was red after forcing",);
return None;
}
None => {}
}
- if !tcx.dep_context().sess().has_errors_or_delayed_span_bugs() {
+ if !qcx.dep_context().sess().has_errors_or_delayed_span_bugs() {
panic!("try_mark_previous_green() - Forcing the DepNode should have set its color")
}
// invalid state will not be persisted to the
// incremental compilation cache because of
// compilation errors being present.
- debug!(
- "try_mark_previous_green({:?}) - END - dependency {:?} resulted in compilation error",
- dep_node, dep_dep_node
- );
+ debug!("dependency {dep_dep_node:?} resulted in compilation error",);
return None;
}
/// Try to mark a dep-node which existed in the previous compilation session as green.
- fn try_mark_previous_green<Ctxt: QueryContext<DepKind = K>>(
+ #[instrument(skip(self, qcx, data, prev_dep_node_index), level = "debug")]
+ fn try_mark_previous_green<Qcx: QueryContext<DepKind = K>>(
&self,
- tcx: Ctxt,
+ qcx: Qcx,
data: &DepGraphData<K>,
prev_dep_node_index: SerializedDepNodeIndex,
dep_node: &DepNode<K>,
) -> Option<DepNodeIndex> {
- debug!("try_mark_previous_green({:?}) - BEGIN", dep_node);
-
#[cfg(not(parallel_compiler))]
{
debug_assert!(!self.dep_node_exists(dep_node));
}
// We never try to mark eval_always nodes as green
- debug_assert!(!tcx.dep_context().is_eval_always(dep_node.kind));
+ debug_assert!(!qcx.dep_context().is_eval_always(dep_node.kind));
debug_assert_eq!(data.previous.index_to_node(prev_dep_node_index), *dep_node);
let prev_deps = data.previous.edge_targets_from(prev_dep_node_index);
for &dep_dep_node_index in prev_deps {
- self.try_mark_parent_green(tcx, data, dep_dep_node_index, dep_node)?
+ self.try_mark_parent_green(qcx, data, dep_dep_node_index, dep_node)?
}
// If we got here without hitting a `return` that means that all
// We allocating an entry for the node in the current dependency graph and
// adding all the appropriate edges imported from the previous graph
let dep_node_index = data.current.promote_node_and_deps_to_current(
- tcx.dep_context().profiler(),
+ qcx.dep_context().profiler(),
&data.previous,
prev_dep_node_index,
);
// FIXME: Store the fact that a node has diagnostics in a bit in the dep graph somewhere
// Maybe store a list on disk and encode this fact in the DepNodeState
- let side_effects = tcx.load_side_effects(prev_dep_node_index);
+ let side_effects = qcx.load_side_effects(prev_dep_node_index);
#[cfg(not(parallel_compiler))]
debug_assert!(
);
if !side_effects.is_empty() {
- self.emit_side_effects(tcx, data, dep_node_index, side_effects);
+ self.emit_side_effects(qcx, data, dep_node_index, side_effects);
}
// ... and finally storing a "Green" entry in the color map.
// Multiple threads can all write the same color here
data.colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index));
- debug!("try_mark_previous_green({:?}) - END - successfully marked as green", dep_node);
+ debug!("successfully marked {dep_node:?} as green");
Some(dep_node_index)
}
/// This may be called concurrently on multiple threads for the same dep node.
#[cold]
#[inline(never)]
- fn emit_side_effects<Ctxt: QueryContext<DepKind = K>>(
+ fn emit_side_effects<Qcx: QueryContext<DepKind = K>>(
&self,
- tcx: Ctxt,
+ qcx: Qcx,
data: &DepGraphData<K>,
dep_node_index: DepNodeIndex,
side_effects: QuerySideEffects,
// must process side effects
// Promote the previous diagnostics to the current session.
- tcx.store_side_effects(dep_node_index, side_effects.clone());
+ qcx.store_side_effects(dep_node_index, side_effects.clone());
- let handle = tcx.dep_context().sess().diagnostic();
+ let handle = qcx.dep_context().sess().diagnostic();
for mut diagnostic in side_effects.diagnostics {
handle.emit_diagnostic(&mut diagnostic);
//
// This method will only load queries that will end up in the disk cache.
// Other queries will not be executed.
- pub fn exec_cache_promotions<Ctxt: DepContext<DepKind = K>>(&self, tcx: Ctxt) {
+ pub fn exec_cache_promotions<Tcx: DepContext<DepKind = K>>(&self, tcx: Tcx) {
let _prof_timer = tcx.profiler().generic_activity("incr_comp_query_cache_promotion");
let data = self.data.as_ref().unwrap();
}
/// Try to force a dep node to execute and see if it's green.
+ #[instrument(skip(self), level = "debug")]
fn try_force_from_dep_node(self, dep_node: DepNode<Self::DepKind>) -> bool {
- debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node);
-
let cb = self.dep_kind_info(dep_node.kind);
if let Some(f) = cb.force_from_dep_node {
f(self, dep_node);
use std::fmt::Debug;
use std::hash::Hash;
-pub trait QueryConfig {
+pub trait QueryConfig<Qcx: QueryContext> {
const NAME: &'static str;
type Key: Eq + Hash + Clone + Debug;
type Value;
type Stored: Clone;
+
+ type Cache: QueryCache<Key = Self::Key, Stored = Self::Stored, Value = Self::Value>;
+
+ // Don't use this method to access query results, instead use the methods on TyCtxt
+ fn query_state<'a>(tcx: Qcx) -> &'a QueryState<Self::Key>
+ where
+ Qcx: 'a;
+
+ // Don't use this method to access query results, instead use the methods on TyCtxt
+ fn query_cache<'a>(tcx: Qcx) -> &'a Self::Cache
+ where
+ Qcx: 'a;
+
+ // Don't use this method to compute query results, instead use the methods on TyCtxt
+ fn make_vtable(tcx: Qcx, key: &Self::Key) -> QueryVTable<Qcx, Self::Key, Self::Value>;
+
+ fn cache_on_disk(tcx: Qcx::DepContext, key: &Self::Key) -> bool;
+
+ // Don't use this method to compute query results, instead use the methods on TyCtxt
+ fn execute_query(tcx: Qcx::DepContext, k: Self::Key) -> Self::Stored;
}
#[derive(Copy, Clone)]
-pub struct QueryVTable<CTX: QueryContext, K, V> {
+pub struct QueryVTable<Qcx: QueryContext, K, V> {
pub anon: bool,
- pub dep_kind: CTX::DepKind,
+ pub dep_kind: Qcx::DepKind,
pub eval_always: bool,
pub depth_limit: bool,
- pub compute: fn(CTX::DepContext, K) -> V,
+ pub compute: fn(Qcx::DepContext, K) -> V,
pub hash_result: Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>,
pub handle_cycle_error: HandleCycleError,
// NOTE: this is also `None` if `cache_on_disk()` returns false, not just if it's unsupported by the query
- pub try_load_from_disk: Option<fn(CTX, SerializedDepNodeIndex) -> Option<V>>,
+ pub try_load_from_disk: Option<fn(Qcx, SerializedDepNodeIndex) -> Option<V>>,
}
-impl<CTX: QueryContext, K, V> QueryVTable<CTX, K, V> {
- pub(crate) fn to_dep_node(&self, tcx: CTX::DepContext, key: &K) -> DepNode<CTX::DepKind>
+impl<Qcx: QueryContext, K, V> QueryVTable<Qcx, K, V> {
+ pub(crate) fn to_dep_node(&self, tcx: Qcx::DepContext, key: &K) -> DepNode<Qcx::DepKind>
where
- K: crate::dep_graph::DepNodeParams<CTX::DepContext>,
+ K: crate::dep_graph::DepNodeParams<Qcx::DepContext>,
{
DepNode::construct(tcx, self.dep_kind, key)
}
- pub(crate) fn compute(&self, tcx: CTX::DepContext, key: K) -> V {
+ pub(crate) fn compute(&self, tcx: Qcx::DepContext, key: K) -> V {
(self.compute)(tcx, key)
}
}
-
-pub trait QueryDescription<CTX: QueryContext>: QueryConfig {
- type Cache: QueryCache<Key = Self::Key, Stored = Self::Stored, Value = Self::Value>;
-
- // Don't use this method to access query results, instead use the methods on TyCtxt
- fn query_state<'a>(tcx: CTX) -> &'a QueryState<Self::Key>
- where
- CTX: 'a;
-
- // Don't use this method to access query results, instead use the methods on TyCtxt
- fn query_cache<'a>(tcx: CTX) -> &'a Self::Cache
- where
- CTX: 'a;
-
- // Don't use this method to compute query results, instead use the methods on TyCtxt
- fn make_vtable(tcx: CTX, key: &Self::Key) -> QueryVTable<CTX, Self::Key, Self::Value>;
-
- fn cache_on_disk(tcx: CTX::DepContext, key: &Self::Key) -> bool;
-
- // Don't use this method to compute query results, instead use the methods on TyCtxt
- fn execute_query(tcx: CTX::DepContext, k: Self::Key) -> Self::Stored;
-}
cycle_diag.into_diagnostic(&sess.parse_sess.span_diagnostic)
}
-pub fn print_query_stack<CTX: QueryContext>(
- tcx: CTX,
+pub fn print_query_stack<Qcx: QueryContext>(
+ qcx: Qcx,
mut current_query: Option<QueryJobId>,
handler: &Handler,
num_frames: Option<usize>,
// a panic hook, which means that the global `Handler` may be in a weird
// state if it was responsible for triggering the panic.
let mut i = 0;
- let query_map = tcx.try_collect_active_jobs();
+ let query_map = qcx.try_collect_active_jobs();
while let Some(query) = current_query {
if Some(i) == num_frames {
};
mod config;
-pub use self::config::{QueryConfig, QueryDescription, QueryVTable};
+pub use self::config::{QueryConfig, QueryVTable};
use crate::dep_graph::{DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
use rustc_data_structures::sync::Lock;
use crate::dep_graph::{DepContext, DepNode, DepNodeIndex, DepNodeParams};
use crate::query::caches::QueryCache;
-use crate::query::config::{QueryDescription, QueryVTable};
+use crate::query::config::QueryVTable;
use crate::query::job::{report_cycle, QueryInfo, QueryJob, QueryJobId, QueryJobInfo};
use crate::query::{QueryContext, QueryMap, QuerySideEffects, QueryStackFrame};
use crate::values::Value;
use std::ptr;
use thin_vec::ThinVec;
+use super::QueryConfig;
+
pub struct QueryState<K> {
#[cfg(parallel_compiler)]
active: Sharded<FxHashMap<K, QueryResult>>,
}
}
- pub fn try_collect_active_jobs<CTX: Copy>(
+ pub fn try_collect_active_jobs<Qcx: Copy>(
&self,
- tcx: CTX,
- make_query: fn(CTX, K) -> QueryStackFrame,
+ qcx: Qcx,
+ make_query: fn(Qcx, K) -> QueryStackFrame,
jobs: &mut QueryMap,
) -> Option<()> {
#[cfg(parallel_compiler)]
for shard in shards.iter() {
for (k, v) in shard.iter() {
if let QueryResult::Started(ref job) = *v {
- let query = make_query(tcx, k.clone());
+ let query = make_query(qcx, k.clone());
jobs.insert(job.id, QueryJobInfo { query, job: job.clone() });
}
}
// really hurt much.)
for (k, v) in self.active.try_lock()?.iter() {
if let QueryResult::Started(ref job) = *v {
- let query = make_query(tcx, k.clone());
+ let query = make_query(qcx, k.clone());
jobs.insert(job.id, QueryJobInfo { query, job: job.clone() });
}
}
#[cold]
#[inline(never)]
-fn mk_cycle<CTX, V, R>(
- tcx: CTX,
+fn mk_cycle<Qcx, V, R>(
+ qcx: Qcx,
cycle_error: CycleError,
handler: HandleCycleError,
cache: &dyn crate::query::QueryStorage<Value = V, Stored = R>,
) -> R
where
- CTX: QueryContext,
- V: std::fmt::Debug + Value<CTX::DepContext>,
+ Qcx: QueryContext,
+ V: std::fmt::Debug + Value<Qcx::DepContext>,
R: Clone,
{
- let error = report_cycle(tcx.dep_context().sess(), &cycle_error);
- let value = handle_cycle_error(*tcx.dep_context(), &cycle_error, error, handler);
+ let error = report_cycle(qcx.dep_context().sess(), &cycle_error);
+ let value = handle_cycle_error(*qcx.dep_context(), &cycle_error, error, handler);
cache.store_nocache(value)
}
-fn handle_cycle_error<CTX, V>(
- tcx: CTX,
+fn handle_cycle_error<Tcx, V>(
+ tcx: Tcx,
cycle_error: &CycleError,
mut error: DiagnosticBuilder<'_, ErrorGuaranteed>,
handler: HandleCycleError,
) -> V
where
- CTX: DepContext,
- V: Value<CTX>,
+ Tcx: DepContext,
+ V: Value<Tcx>,
{
use HandleCycleError::*;
match handler {
/// This function is inlined because that results in a noticeable speed-up
/// for some compile-time benchmarks.
#[inline(always)]
- fn try_start<'b, CTX>(
- tcx: &'b CTX,
+ fn try_start<'b, Qcx>(
+ qcx: &'b Qcx,
state: &'b QueryState<K>,
span: Span,
key: K,
) -> TryGetJob<'b, K>
where
- CTX: QueryContext,
+ Qcx: QueryContext,
{
#[cfg(parallel_compiler)]
let mut state_lock = state.active.get_shard_by_value(&key).lock();
match lock.entry(key) {
Entry::Vacant(entry) => {
- let id = tcx.next_job_id();
- let job = tcx.current_query_job();
+ let id = qcx.next_job_id();
+ let job = qcx.current_query_job();
let job = QueryJob::new(id, span, job);
let key = entry.key().clone();
// If we are single-threaded we know that we have cycle error,
// so we just return the error.
return TryGetJob::Cycle(id.find_cycle_in_stack(
- tcx.try_collect_active_jobs().unwrap(),
- &tcx.current_query_job(),
+ qcx.try_collect_active_jobs().unwrap(),
+ &qcx.current_query_job(),
span,
));
}
// For parallel queries, we'll block and wait until the query running
// in another thread has completed. Record how long we wait in the
// self-profiler.
- let query_blocked_prof_timer = tcx.dep_context().profiler().query_blocked();
+ let query_blocked_prof_timer = qcx.dep_context().profiler().query_blocked();
// Get the latch out
let latch = job.latch();
// With parallel queries we might just have to wait on some other
// thread.
- let result = latch.wait_on(tcx.current_query_job(), span);
+ let result = latch.wait_on(qcx.current_query_job(), span);
match result {
Ok(()) => TryGetJob::JobCompleted(query_blocked_prof_timer),
/// which will be used if the query is not in the cache and we need
/// to compute it.
#[inline]
-pub fn try_get_cached<'a, CTX, C, R, OnHit>(
- tcx: CTX,
+pub fn try_get_cached<'a, Tcx, C, R, OnHit>(
+ tcx: Tcx,
cache: &'a C,
key: &C::Key,
// `on_hit` can be called while holding a lock to the query cache
) -> Result<R, ()>
where
C: QueryCache,
- CTX: DepContext,
+ Tcx: DepContext,
OnHit: FnOnce(&C::Stored) -> R,
{
cache.lookup(&key, |value, index| {
})
}
-fn try_execute_query<CTX, C>(
- tcx: CTX,
+fn try_execute_query<Qcx, C>(
+ qcx: Qcx,
state: &QueryState<C::Key>,
cache: &C,
span: Span,
key: C::Key,
- dep_node: Option<DepNode<CTX::DepKind>>,
- query: &QueryVTable<CTX, C::Key, C::Value>,
+ dep_node: Option<DepNode<Qcx::DepKind>>,
+ query: &QueryVTable<Qcx, C::Key, C::Value>,
) -> (C::Stored, Option<DepNodeIndex>)
where
C: QueryCache,
- C::Key: Clone + DepNodeParams<CTX::DepContext>,
- C::Value: Value<CTX::DepContext>,
- CTX: QueryContext,
+ C::Key: Clone + DepNodeParams<Qcx::DepContext>,
+ C::Value: Value<Qcx::DepContext>,
+ Qcx: QueryContext,
{
- match JobOwner::<'_, C::Key>::try_start(&tcx, state, span, key.clone()) {
+ match JobOwner::<'_, C::Key>::try_start(&qcx, state, span, key.clone()) {
TryGetJob::NotYetStarted(job) => {
- let (result, dep_node_index) = execute_job(tcx, key, dep_node, query, job.id);
+ let (result, dep_node_index) = execute_job(qcx, key, dep_node, query, job.id);
let result = job.complete(cache, result, dep_node_index);
(result, Some(dep_node_index))
}
TryGetJob::Cycle(error) => {
- let result = mk_cycle(tcx, error, query.handle_cycle_error, cache);
+ let result = mk_cycle(qcx, error, query.handle_cycle_error, cache);
(result, None)
}
#[cfg(parallel_compiler)]
.lookup(&key, |value, index| (value.clone(), index))
.unwrap_or_else(|_| panic!("value must be in cache after waiting"));
- if std::intrinsics::unlikely(tcx.dep_context().profiler().enabled()) {
- tcx.dep_context().profiler().query_cache_hit(index.into());
+ if std::intrinsics::unlikely(qcx.dep_context().profiler().enabled()) {
+ qcx.dep_context().profiler().query_cache_hit(index.into());
}
query_blocked_prof_timer.finish_with_query_invocation_id(index.into());
}
}
-fn execute_job<CTX, K, V>(
- tcx: CTX,
+fn execute_job<Qcx, K, V>(
+ qcx: Qcx,
key: K,
- mut dep_node_opt: Option<DepNode<CTX::DepKind>>,
- query: &QueryVTable<CTX, K, V>,
+ mut dep_node_opt: Option<DepNode<Qcx::DepKind>>,
+ query: &QueryVTable<Qcx, K, V>,
job_id: QueryJobId,
) -> (V, DepNodeIndex)
where
- K: Clone + DepNodeParams<CTX::DepContext>,
+ K: Clone + DepNodeParams<Qcx::DepContext>,
V: Debug,
- CTX: QueryContext,
+ Qcx: QueryContext,
{
- let dep_graph = tcx.dep_context().dep_graph();
+ let dep_graph = qcx.dep_context().dep_graph();
// Fast path for when incr. comp. is off.
if !dep_graph.is_fully_enabled() {
- let prof_timer = tcx.dep_context().profiler().query_provider();
- let result = tcx.start_query(job_id, query.depth_limit, None, || {
- query.compute(*tcx.dep_context(), key)
+ let prof_timer = qcx.dep_context().profiler().query_provider();
+ let result = qcx.start_query(job_id, query.depth_limit, None, || {
+ query.compute(*qcx.dep_context(), key)
});
let dep_node_index = dep_graph.next_virtual_depnode_index();
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
if !query.anon && !query.eval_always {
// `to_dep_node` is expensive for some `DepKind`s.
let dep_node =
- dep_node_opt.get_or_insert_with(|| query.to_dep_node(*tcx.dep_context(), &key));
+ dep_node_opt.get_or_insert_with(|| query.to_dep_node(*qcx.dep_context(), &key));
// The diagnostics for this query will be promoted to the current session during
// `try_mark_green()`, so we can ignore them here.
- if let Some(ret) = tcx.start_query(job_id, false, None, || {
- try_load_from_disk_and_cache_in_memory(tcx, &key, &dep_node, query)
+ if let Some(ret) = qcx.start_query(job_id, false, None, || {
+ try_load_from_disk_and_cache_in_memory(qcx, &key, &dep_node, query)
}) {
return ret;
}
}
- let prof_timer = tcx.dep_context().profiler().query_provider();
+ let prof_timer = qcx.dep_context().profiler().query_provider();
let diagnostics = Lock::new(ThinVec::new());
let (result, dep_node_index) =
- tcx.start_query(job_id, query.depth_limit, Some(&diagnostics), || {
+ qcx.start_query(job_id, query.depth_limit, Some(&diagnostics), || {
if query.anon {
- return dep_graph.with_anon_task(*tcx.dep_context(), query.dep_kind, || {
- query.compute(*tcx.dep_context(), key)
+ return dep_graph.with_anon_task(*qcx.dep_context(), query.dep_kind, || {
+ query.compute(*qcx.dep_context(), key)
});
}
// `to_dep_node` is expensive for some `DepKind`s.
let dep_node =
- dep_node_opt.unwrap_or_else(|| query.to_dep_node(*tcx.dep_context(), &key));
+ dep_node_opt.unwrap_or_else(|| query.to_dep_node(*qcx.dep_context(), &key));
- dep_graph.with_task(dep_node, *tcx.dep_context(), key, query.compute, query.hash_result)
+ dep_graph.with_task(dep_node, *qcx.dep_context(), key, query.compute, query.hash_result)
});
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
if std::intrinsics::unlikely(!side_effects.is_empty()) {
if query.anon {
- tcx.store_side_effects_for_anon_node(dep_node_index, side_effects);
+ qcx.store_side_effects_for_anon_node(dep_node_index, side_effects);
} else {
- tcx.store_side_effects(dep_node_index, side_effects);
+ qcx.store_side_effects(dep_node_index, side_effects);
}
}
(result, dep_node_index)
}
-fn try_load_from_disk_and_cache_in_memory<CTX, K, V>(
- tcx: CTX,
+fn try_load_from_disk_and_cache_in_memory<Qcx, K, V>(
+ qcx: Qcx,
key: &K,
- dep_node: &DepNode<CTX::DepKind>,
- query: &QueryVTable<CTX, K, V>,
+ dep_node: &DepNode<Qcx::DepKind>,
+ query: &QueryVTable<Qcx, K, V>,
) -> Option<(V, DepNodeIndex)>
where
K: Clone,
- CTX: QueryContext,
+ Qcx: QueryContext,
V: Debug,
{
// Note this function can be called concurrently from the same query
// We must ensure that this is handled correctly.
- let dep_graph = tcx.dep_context().dep_graph();
- let (prev_dep_node_index, dep_node_index) = dep_graph.try_mark_green(tcx, &dep_node)?;
+ let dep_graph = qcx.dep_context().dep_graph();
+ let (prev_dep_node_index, dep_node_index) = dep_graph.try_mark_green(qcx, &dep_node)?;
debug_assert!(dep_graph.is_green(dep_node));
// First we try to load the result from the on-disk cache.
// Some things are never cached on disk.
if let Some(try_load_from_disk) = query.try_load_from_disk {
- let prof_timer = tcx.dep_context().profiler().incr_cache_loading();
+ let prof_timer = qcx.dep_context().profiler().incr_cache_loading();
// The call to `with_query_deserialization` enforces that no new `DepNodes`
// are created during deserialization. See the docs of that method for more
// details.
let result =
- dep_graph.with_query_deserialization(|| try_load_from_disk(tcx, prev_dep_node_index));
+ dep_graph.with_query_deserialization(|| try_load_from_disk(qcx, prev_dep_node_index));
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
if let Some(result) = result {
if std::intrinsics::unlikely(
- tcx.dep_context().sess().opts.unstable_opts.query_dep_graph,
+ qcx.dep_context().sess().opts.unstable_opts.query_dep_graph,
) {
dep_graph.mark_debug_loaded_from_disk(*dep_node)
}
- let prev_fingerprint = tcx
+ let prev_fingerprint = qcx
.dep_context()
.dep_graph()
.prev_fingerprint_of(dep_node)
// give us some coverage of potential bugs though.
let try_verify = prev_fingerprint.as_value().1 % 32 == 0;
if std::intrinsics::unlikely(
- try_verify || tcx.dep_context().sess().opts.unstable_opts.incremental_verify_ich,
+ try_verify || qcx.dep_context().sess().opts.unstable_opts.incremental_verify_ich,
) {
- incremental_verify_ich(*tcx.dep_context(), &result, dep_node, query);
+ incremental_verify_ich(*qcx.dep_context(), &result, dep_node, query);
}
return Some((result, dep_node_index));
// We always expect to find a cached result for things that
// can be forced from `DepNode`.
debug_assert!(
- !tcx.dep_context().fingerprint_style(dep_node.kind).reconstructible(),
+ !qcx.dep_context().fingerprint_style(dep_node.kind).reconstructible(),
"missing on-disk cache entry for {:?}",
dep_node
);
// We could not load a result from the on-disk cache, so
// recompute.
- let prof_timer = tcx.dep_context().profiler().query_provider();
+ let prof_timer = qcx.dep_context().profiler().query_provider();
// The dep-graph for this computation is already in-place.
- let result = dep_graph.with_ignore(|| query.compute(*tcx.dep_context(), key.clone()));
+ let result = dep_graph.with_ignore(|| query.compute(*qcx.dep_context(), key.clone()));
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
//
// See issue #82920 for an example of a miscompilation that would get turned into
// an ICE by this check
- incremental_verify_ich(*tcx.dep_context(), &result, dep_node, query);
+ incremental_verify_ich(*qcx.dep_context(), &result, dep_node, query);
Some((result, dep_node_index))
}
-fn incremental_verify_ich<CTX, K, V: Debug>(
- tcx: CTX::DepContext,
+#[instrument(skip(qcx, result, query), level = "debug")]
+fn incremental_verify_ich<Qcx, K, V: Debug>(
+ qcx: Qcx::DepContext,
result: &V,
- dep_node: &DepNode<CTX::DepKind>,
- query: &QueryVTable<CTX, K, V>,
+ dep_node: &DepNode<Qcx::DepKind>,
+ query: &QueryVTable<Qcx, K, V>,
) where
- CTX: QueryContext,
+ Qcx: QueryContext,
{
assert!(
- tcx.dep_graph().is_green(dep_node),
+ qcx.dep_graph().is_green(dep_node),
"fingerprint for green query instance not loaded from cache: {:?}",
dep_node,
);
- debug!("BEGIN verify_ich({:?})", dep_node);
let new_hash = query.hash_result.map_or(Fingerprint::ZERO, |f| {
- tcx.with_stable_hashing_context(|mut hcx| f(&mut hcx, result))
+ qcx.with_stable_hashing_context(|mut hcx| f(&mut hcx, result))
});
- let old_hash = tcx.dep_graph().prev_fingerprint_of(dep_node);
- debug!("END verify_ich({:?})", dep_node);
+
+ let old_hash = qcx.dep_graph().prev_fingerprint_of(dep_node);
if Some(new_hash) != old_hash {
- incremental_verify_ich_cold(tcx.sess(), DebugArg::from(&dep_node), DebugArg::from(&result));
+ incremental_verify_ich_failed(
+ qcx.sess(),
+ DebugArg::from(&dep_node),
+ DebugArg::from(&result),
+ );
}
}
// different implementations for LLVM to chew on (and filling up the final
// binary, too).
#[cold]
-fn incremental_verify_ich_cold(sess: &Session, dep_node: DebugArg<'_>, result: DebugArg<'_>) {
- let run_cmd = if let Some(crate_name) = &sess.opts.crate_name {
- format!("`cargo clean -p {}` or `cargo clean`", crate_name)
- } else {
- "`cargo clean`".to_string()
- };
-
+fn incremental_verify_ich_failed(sess: &Session, dep_node: DebugArg<'_>, result: DebugArg<'_>) {
// When we emit an error message and panic, we try to debug-print the `DepNode`
// and query result. Unfortunately, this can cause us to run additional queries,
// which may result in another fingerprint mismatch while we're in the middle
if old_in_panic {
sess.emit_err(crate::error::Reentrant);
} else {
+ let run_cmd = if let Some(crate_name) = &sess.opts.crate_name {
+ format!("`cargo clean -p {}` or `cargo clean`", crate_name)
+ } else {
+ "`cargo clean`".to_string()
+ };
+
sess.emit_err(crate::error::IncrementCompilation {
run_cmd,
dep_node: format!("{:?}", dep_node),
///
/// Note: The optimization is only available during incr. comp.
#[inline(never)]
-fn ensure_must_run<CTX, K, V>(
- tcx: CTX,
+fn ensure_must_run<Qcx, K, V>(
+ qcx: Qcx,
key: &K,
- query: &QueryVTable<CTX, K, V>,
-) -> (bool, Option<DepNode<CTX::DepKind>>)
+ query: &QueryVTable<Qcx, K, V>,
+) -> (bool, Option<DepNode<Qcx::DepKind>>)
where
- K: crate::dep_graph::DepNodeParams<CTX::DepContext>,
- CTX: QueryContext,
+ K: crate::dep_graph::DepNodeParams<Qcx::DepContext>,
+ Qcx: QueryContext,
{
if query.eval_always {
return (true, None);
// Ensuring an anonymous query makes no sense
assert!(!query.anon);
- let dep_node = query.to_dep_node(*tcx.dep_context(), key);
+ let dep_node = query.to_dep_node(*qcx.dep_context(), key);
- let dep_graph = tcx.dep_context().dep_graph();
- match dep_graph.try_mark_green(tcx, &dep_node) {
+ let dep_graph = qcx.dep_context().dep_graph();
+ match dep_graph.try_mark_green(qcx, &dep_node) {
None => {
// A None return from `try_mark_green` means that this is either
// a new dep node or that the dep node has already been marked red.
}
Some((_, dep_node_index)) => {
dep_graph.read_index(dep_node_index);
- tcx.dep_context().profiler().query_cache_hit(dep_node_index.into());
+ qcx.dep_context().profiler().query_cache_hit(dep_node_index.into());
(false, None)
}
}
Ensure,
}
-pub fn get_query<Q, CTX>(tcx: CTX, span: Span, key: Q::Key, mode: QueryMode) -> Option<Q::Stored>
+pub fn get_query<Q, Qcx>(qcx: Qcx, span: Span, key: Q::Key, mode: QueryMode) -> Option<Q::Stored>
where
- Q: QueryDescription<CTX>,
- Q::Key: DepNodeParams<CTX::DepContext>,
- Q::Value: Value<CTX::DepContext>,
- CTX: QueryContext,
+ Q: QueryConfig<Qcx>,
+ Q::Key: DepNodeParams<Qcx::DepContext>,
+ Q::Value: Value<Qcx::DepContext>,
+ Qcx: QueryContext,
{
- let query = Q::make_vtable(tcx, &key);
+ let query = Q::make_vtable(qcx, &key);
let dep_node = if let QueryMode::Ensure = mode {
- let (must_run, dep_node) = ensure_must_run(tcx, &key, &query);
+ let (must_run, dep_node) = ensure_must_run(qcx, &key, &query);
if !must_run {
return None;
}
};
let (result, dep_node_index) = try_execute_query(
- tcx,
- Q::query_state(tcx),
- Q::query_cache(tcx),
+ qcx,
+ Q::query_state(qcx),
+ Q::query_cache(qcx),
span,
key,
dep_node,
&query,
);
if let Some(dep_node_index) = dep_node_index {
- tcx.dep_context().dep_graph().read_index(dep_node_index)
+ qcx.dep_context().dep_graph().read_index(dep_node_index)
}
Some(result)
}
-pub fn force_query<Q, CTX>(tcx: CTX, key: Q::Key, dep_node: DepNode<CTX::DepKind>)
+pub fn force_query<Q, Qcx>(qcx: Qcx, key: Q::Key, dep_node: DepNode<Qcx::DepKind>)
where
- Q: QueryDescription<CTX>,
- Q::Key: DepNodeParams<CTX::DepContext>,
- Q::Value: Value<CTX::DepContext>,
- CTX: QueryContext,
+ Q: QueryConfig<Qcx>,
+ Q::Key: DepNodeParams<Qcx::DepContext>,
+ Q::Value: Value<Qcx::DepContext>,
+ Qcx: QueryContext,
{
// We may be concurrently trying both execute and force a query.
// Ensure that only one of them runs the query.
- let cache = Q::query_cache(tcx);
+ let cache = Q::query_cache(qcx);
let cached = cache.lookup(&key, |_, index| {
- if std::intrinsics::unlikely(tcx.dep_context().profiler().enabled()) {
- tcx.dep_context().profiler().query_cache_hit(index.into());
+ if std::intrinsics::unlikely(qcx.dep_context().profiler().enabled()) {
+ qcx.dep_context().profiler().query_cache_hit(index.into());
}
});
Err(()) => {}
}
- let query = Q::make_vtable(tcx, &key);
- let state = Q::query_state(tcx);
+ let query = Q::make_vtable(qcx, &key);
+ let state = Q::query_state(qcx);
debug_assert!(!query.anon);
- try_execute_query(tcx, state, cache, DUMMY_SP, key, Some(dep_node), &query);
+ try_execute_query(qcx, state, cache, DUMMY_SP, key, Some(dep_node), &query);
}
use crate::dep_graph::DepContext;
use crate::query::QueryInfo;
-pub trait Value<CTX: DepContext>: Sized {
- fn from_cycle_error(tcx: CTX, cycle: &[QueryInfo]) -> Self;
+pub trait Value<Tcx: DepContext>: Sized {
+ fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo]) -> Self;
}
-impl<CTX: DepContext, T> Value<CTX> for T {
- default fn from_cycle_error(tcx: CTX, _: &[QueryInfo]) -> T {
+impl<Tcx: DepContext, T> Value<Tcx> for T {
+ default fn from_cycle_error(tcx: Tcx, _: &[QueryInfo]) -> T {
tcx.sess().abort_if_errors();
// Ideally we would use `bug!` here. But bug! is only defined in rustc_middle, and it's
// non-trivial to define it earlier.
+++ /dev/null
-use crate::{ImportKind, NameBindingKind, Resolver};
-use rustc_ast::ast;
-use rustc_ast::visit;
-use rustc_ast::visit::Visitor;
-use rustc_ast::Crate;
-use rustc_ast::EnumDef;
-use rustc_hir::def_id::LocalDefId;
-use rustc_hir::def_id::CRATE_DEF_ID;
-use rustc_middle::middle::privacy::AccessLevel;
-use rustc_middle::ty::{DefIdTree, Visibility};
-
-pub struct AccessLevelsVisitor<'r, 'a> {
- r: &'r mut Resolver<'a>,
- changed: bool,
-}
-
-impl<'r, 'a> AccessLevelsVisitor<'r, 'a> {
- /// Fills the `Resolver::access_levels` table with public & exported items
- /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
- /// need access to a TyCtxt for that.
- pub fn compute_access_levels<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) {
- let mut visitor = AccessLevelsVisitor { r, changed: false };
-
- visitor.update(CRATE_DEF_ID, Visibility::Public, CRATE_DEF_ID, AccessLevel::Public);
- visitor.set_bindings_access_level(CRATE_DEF_ID);
-
- while visitor.changed {
- visitor.reset();
- visit::walk_crate(&mut visitor, krate);
- }
-
- info!("resolve::access_levels: {:#?}", r.access_levels);
- }
-
- fn reset(&mut self) {
- self.changed = false;
- }
-
- /// Update the access level of the bindings in the given module accordingly. The module access
- /// level has to be Exported or Public.
- /// This will also follow `use` chains (see PrivacyVisitor::set_import_binding_access_level).
- fn set_bindings_access_level(&mut self, module_id: LocalDefId) {
- assert!(self.r.module_map.contains_key(&&module_id.to_def_id()));
- let module = self.r.get_module(module_id.to_def_id()).unwrap();
- let resolutions = self.r.resolutions(module);
-
- for (_, name_resolution) in resolutions.borrow().iter() {
- if let Some(mut binding) = name_resolution.borrow().binding() && !binding.is_ambiguity() {
- // Set the given binding access level to `AccessLevel::Public` and
- // sets the rest of the `use` chain to `AccessLevel::Exported` until
- // we hit the actual exported item.
-
- // FIXME: tag and is_public() condition should be removed, but assertions occur.
- let tag = if binding.is_import() { AccessLevel::Exported } else { AccessLevel::Public };
- if binding.vis.is_public() {
- let mut prev_parent_id = module_id;
- let mut level = AccessLevel::Public;
- while let NameBindingKind::Import { binding: nested_binding, import, .. } =
- binding.kind
- {
- let mut update = |node_id| self.update(
- self.r.local_def_id(node_id),
- binding.vis.expect_local(),
- prev_parent_id,
- level,
- );
- // In theory all the import IDs have individual visibilities and effective
- // visibilities, but in practice these IDs go straigth to HIR where all
- // their few uses assume that their (effective) visibility applies to the
- // whole syntactic `use` item. So we update them all to the maximum value
- // among the potential individual effective visibilities. Maybe HIR for
- // imports shouldn't use three IDs at all.
- update(import.id);
- if let ImportKind::Single { additional_ids, .. } = import.kind {
- update(additional_ids.0);
- update(additional_ids.1);
- }
-
- level = AccessLevel::Exported;
- prev_parent_id = self.r.local_def_id(import.id);
- binding = nested_binding;
- }
- }
-
- if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) {
- self.update(def_id, binding.vis.expect_local(), module_id, tag);
- }
- }
- }
- }
-
- fn update(
- &mut self,
- def_id: LocalDefId,
- nominal_vis: Visibility,
- parent_id: LocalDefId,
- tag: AccessLevel,
- ) {
- let module_id = self
- .r
- .get_nearest_non_block_module(def_id.to_def_id())
- .nearest_parent_mod()
- .expect_local();
- if nominal_vis == Visibility::Restricted(module_id)
- || self.r.visibilities[&parent_id] == Visibility::Restricted(module_id)
- {
- return;
- }
- let mut access_levels = std::mem::take(&mut self.r.access_levels);
- self.changed |= access_levels.update(
- def_id,
- nominal_vis,
- || Visibility::Restricted(module_id),
- parent_id,
- tag,
- &*self.r,
- );
- self.r.access_levels = access_levels;
- }
-}
-
-impl<'r, 'ast> Visitor<'ast> for AccessLevelsVisitor<'ast, 'r> {
- fn visit_item(&mut self, item: &'ast ast::Item) {
- let def_id = self.r.local_def_id(item.id);
- // Set access level of nested items.
- // If it's a mod, also make the visitor walk all of its items
- match item.kind {
- // Resolved in rustc_privacy when types are available
- ast::ItemKind::Impl(..) => return,
-
- // Should be unreachable at this stage
- ast::ItemKind::MacCall(..) => panic!(
- "ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
- ),
-
- // Foreign modules inherit level from parents.
- ast::ItemKind::ForeignMod(..) => {
- let parent_id = self.r.local_parent(def_id);
- self.update(def_id, Visibility::Public, parent_id, AccessLevel::Public);
- }
-
- // Only exported `macro_rules!` items are public, but they always are
- ast::ItemKind::MacroDef(ref macro_def) if macro_def.macro_rules => {
- let parent_id = self.r.local_parent(def_id);
- let vis = self.r.visibilities[&def_id];
- self.update(def_id, vis, parent_id, AccessLevel::Public);
- }
-
- ast::ItemKind::Mod(..) => {
- self.set_bindings_access_level(def_id);
- visit::walk_item(self, item);
- }
-
- ast::ItemKind::Enum(EnumDef { ref variants }, _) => {
- self.set_bindings_access_level(def_id);
- for variant in variants {
- let variant_def_id = self.r.local_def_id(variant.id);
- for field in variant.data.fields() {
- let field_def_id = self.r.local_def_id(field.id);
- let vis = self.r.visibilities[&field_def_id];
- self.update(field_def_id, vis, variant_def_id, AccessLevel::Public);
- }
- }
- }
-
- ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => {
- for field in def.fields() {
- let field_def_id = self.r.local_def_id(field.id);
- let vis = self.r.visibilities[&field_def_id];
- self.update(field_def_id, vis, def_id, AccessLevel::Public);
- }
- }
-
- ast::ItemKind::Trait(..) => {
- self.set_bindings_access_level(def_id);
- }
-
- ast::ItemKind::ExternCrate(..)
- | ast::ItemKind::Use(..)
- | ast::ItemKind::Static(..)
- | ast::ItemKind::Const(..)
- | ast::ItemKind::GlobalAsm(..)
- | ast::ItemKind::TyAlias(..)
- | ast::ItemKind::TraitAlias(..)
- | ast::ItemKind::MacroDef(..)
- | ast::ItemKind::Fn(..) => return,
- }
- }
-}
impl<'a, Id: Into<DefId>> ToNameBinding<'a> for (Res, ty::Visibility<Id>, Span, LocalExpnId) {
fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> {
arenas.alloc_name_binding(NameBinding {
- kind: NameBindingKind::Res(self.0, false),
- ambiguity: None,
- vis: self.1.to_def_id(),
- span: self.2,
- expansion: self.3,
- })
- }
-}
-
-struct IsMacroExport;
-
-impl<'a> ToNameBinding<'a> for (Res, ty::Visibility, Span, LocalExpnId, IsMacroExport) {
- fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> {
- arenas.alloc_name_binding(NameBinding {
- kind: NameBindingKind::Res(self.0, true),
+ kind: NameBindingKind::Res(self.0),
ambiguity: None,
vis: self.1.to_def_id(),
span: self.2,
module_path: Vec<Segment>,
kind: ImportKind<'a>,
span: Span,
- id: NodeId,
item: &ast::Item,
root_span: Span,
root_id: NodeId,
module_path,
imported_module: Cell::new(None),
span,
- id,
use_span: item.span,
use_span_with_attributes: item.span_with_attributes(),
has_attributes: !item.attrs.is_empty(),
},
type_ns_only,
nested,
+ id,
additional_ids: (id1, id2),
};
- self.add_import(
- module_path,
- kind,
- use_tree.span,
- id,
- item,
- root_span,
- item.id,
- vis,
- );
+ self.add_import(module_path, kind, use_tree.span, item, root_span, item.id, vis);
}
ast::UseTreeKind::Glob => {
let kind = ImportKind::Glob {
is_prelude: self.r.session.contains_name(&item.attrs, sym::prelude_import),
max_vis: Cell::new(None),
+ id,
};
self.r.visibilities.insert(self.r.local_def_id(id), vis);
- self.add_import(prefix, kind, use_tree.span, id, item, root_span, item.id, vis);
+ self.add_import(prefix, kind, use_tree.span, item, root_span, item.id, vis);
}
ast::UseTreeKind::Nested(ref items) => {
// Ensure there is at most one `self` in the list
})
.unwrap_or((true, None, self.r.dummy_binding));
let import = self.r.arenas.alloc_import(Import {
- kind: ImportKind::ExternCrate { source: orig_name, target: ident },
+ kind: ImportKind::ExternCrate { source: orig_name, target: ident, id: item.id },
root_id: item.id,
- id: item.id,
parent_scope: self.parent_scope,
imported_module: Cell::new(module),
has_attributes: !item.attrs.is_empty(),
this.r.arenas.alloc_import(Import {
kind: ImportKind::MacroUse,
root_id: item.id,
- id: item.id,
parent_scope: this.parent_scope,
imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))),
use_span_with_attributes: item.span_with_attributes(),
let binding = (res, vis, span, expansion).to_name_binding(self.r.arenas);
self.r.set_binding_parent_module(binding, parent_scope.module);
if is_macro_export {
- let module = self.r.graph_root;
- self.r.define(module, ident, MacroNS, (res, vis, span, expansion, IsMacroExport));
+ let import = self.r.arenas.alloc_import(Import {
+ kind: ImportKind::MacroExport,
+ root_id: item.id,
+ parent_scope: self.parent_scope,
+ imported_module: Cell::new(None),
+ has_attributes: false,
+ use_span_with_attributes: span,
+ use_span: span,
+ root_span: span,
+ span: span,
+ module_path: Vec::new(),
+ vis: Cell::new(Some(vis)),
+ used: Cell::new(true),
+ });
+ let import_binding = self.r.import(binding, import);
+ self.r.define(self.r.graph_root, ident, MacroNS, import_binding);
} else {
self.r.check_reserved_macro_name(ident, res);
self.insert_unused_macro(ident, def_id, item.id, &rule_spans);
if !import.span.is_dummy() {
self.lint_buffer.buffer_lint(
MACRO_USE_EXTERN_CRATE,
- import.id,
+ import.root_id,
import.span,
"deprecated `#[macro_use]` attribute used to \
import macros should be replaced at use sites \
}
}
}
- ImportKind::ExternCrate { .. } => {
- let def_id = self.local_def_id(import.id);
+ ImportKind::ExternCrate { id, .. } => {
+ let def_id = self.local_def_id(id);
self.maybe_unused_extern_crates.push((def_id, import.span));
}
ImportKind::MacroUse => {
let msg = "unused `#[macro_use]` import";
- self.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.id, import.span, msg);
+ self.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.root_id, import.span, msg);
}
_ => {}
}
#[derive(Debug)]
pub(crate) struct TypoSuggestion {
pub candidate: Symbol,
+ /// The source location where the name is defined; None if the name is not defined
+ /// in source e.g. primitives
+ pub span: Option<Span>,
pub res: Res,
pub target: SuggestionTarget,
}
impl TypoSuggestion {
- pub(crate) fn typo_from_res(candidate: Symbol, res: Res) -> TypoSuggestion {
- Self { candidate, res, target: SuggestionTarget::SimilarlyNamed }
+ pub(crate) fn typo_from_ident(ident: Ident, res: Res) -> TypoSuggestion {
+ Self {
+ candidate: ident.name,
+ span: Some(ident.span),
+ res,
+ target: SuggestionTarget::SimilarlyNamed,
+ }
+ }
+ pub(crate) fn typo_from_name(candidate: Symbol, res: Res) -> TypoSuggestion {
+ Self { candidate, span: None, res, target: SuggestionTarget::SimilarlyNamed }
}
- pub(crate) fn single_item_from_res(candidate: Symbol, res: Res) -> TypoSuggestion {
- Self { candidate, res, target: SuggestionTarget::SingleItem }
+ pub(crate) fn single_item_from_ident(ident: Ident, res: Res) -> TypoSuggestion {
+ Self {
+ candidate: ident.name,
+ span: Some(ident.span),
+ res,
+ target: SuggestionTarget::SingleItem,
+ }
}
}
ModuleKind::Block => "block",
};
- let old_noun = match old_binding.is_import() {
+ let old_noun = match old_binding.is_import_user_facing() {
true => "import",
false => "definition",
};
- let new_participle = match new_binding.is_import() {
+ let new_participle = match new_binding.is_import_user_facing() {
true => "imported",
false => "defined",
};
true => struct_span_err!(self.session, span, E0254, "{}", msg),
false => struct_span_err!(self.session, span, E0260, "{}", msg),
},
- _ => match (old_binding.is_import(), new_binding.is_import()) {
+ _ => match (old_binding.is_import_user_facing(), new_binding.is_import_user_facing()) {
(false, false) => struct_span_err!(self.session, span, E0428, "{}", msg),
(true, true) => struct_span_err!(self.session, span, E0252, "{}", msg),
_ => struct_span_err!(self.session, span, E0255, "{}", msg),
// See https://github.com/rust-lang/rust/issues/32354
use NameBindingKind::Import;
+ let can_suggest = |binding: &NameBinding<'_>, import: &self::Import<'_>| {
+ !binding.span.is_dummy()
+ && !matches!(import.kind, ImportKind::MacroUse | ImportKind::MacroExport)
+ };
let import = match (&new_binding.kind, &old_binding.kind) {
// If there are two imports where one or both have attributes then prefer removing the
// import without attributes.
(Import { import: new, .. }, Import { import: old, .. })
if {
- !new_binding.span.is_dummy()
- && !old_binding.span.is_dummy()
- && (new.has_attributes || old.has_attributes)
+ (new.has_attributes || old.has_attributes)
+ && can_suggest(old_binding, old)
+ && can_suggest(new_binding, new)
} =>
{
if old.has_attributes {
}
}
// Otherwise prioritize the new binding.
- (Import { import, .. }, other) if !new_binding.span.is_dummy() => {
+ (Import { import, .. }, other) if can_suggest(new_binding, import) => {
Some((import, new_binding.span, other.is_import()))
}
- (other, Import { import, .. }) if !old_binding.span.is_dummy() => {
+ (other, Import { import, .. }) if can_suggest(old_binding, import) => {
Some((import, old_binding.span, other.is_import()))
}
_ => None,
}
}
}
- ImportKind::ExternCrate { source, target } => {
+ ImportKind::ExternCrate { source, target, .. } => {
suggestion = Some(format!(
"extern crate {} as {};",
source.unwrap_or(target.name),
if let Some(binding) = resolution.borrow().binding {
let res = binding.res();
if filter_fn(res) && ctxt.map_or(true, |ctxt| ctxt == key.ident.span.ctxt()) {
- names.push(TypoSuggestion::typo_from_res(key.ident.name, res));
+ names.push(TypoSuggestion::typo_from_ident(key.ident, res));
}
}
}
.get(&expn_id)
.into_iter()
.flatten()
- .map(|ident| TypoSuggestion::typo_from_res(ident.name, res)),
+ .map(|ident| TypoSuggestion::typo_from_ident(*ident, res)),
);
}
}
suggestions.extend(
ext.helper_attrs
.iter()
- .map(|name| TypoSuggestion::typo_from_res(*name, res)),
+ .map(|name| TypoSuggestion::typo_from_name(*name, res)),
);
}
}
if let MacroRulesScope::Binding(macro_rules_binding) = macro_rules_scope.get() {
let res = macro_rules_binding.binding.res();
if filter_fn(res) {
- suggestions.push(TypoSuggestion::typo_from_res(
- macro_rules_binding.ident.name,
+ suggestions.push(TypoSuggestion::typo_from_ident(
+ macro_rules_binding.ident,
res,
))
}
let root_module = this.resolve_crate_root(root_ident);
this.add_module_candidates(root_module, &mut suggestions, filter_fn, None);
}
- Scope::Module(module, _) => {
+ Scope::Module(module) => {
this.add_module_candidates(module, &mut suggestions, filter_fn, None);
}
Scope::MacroUsePrelude => {
suggestions.extend(this.macro_use_prelude.iter().filter_map(
|(name, binding)| {
let res = binding.res();
- filter_fn(res).then_some(TypoSuggestion::typo_from_res(*name, res))
+ filter_fn(res).then_some(TypoSuggestion::typo_from_name(*name, res))
},
));
}
suggestions.extend(
BUILTIN_ATTRIBUTES
.iter()
- .map(|attr| TypoSuggestion::typo_from_res(attr.name, res)),
+ .map(|attr| TypoSuggestion::typo_from_name(attr.name, res)),
);
}
}
Scope::ExternPrelude => {
suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| {
let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id());
- filter_fn(res).then_some(TypoSuggestion::typo_from_res(ident.name, res))
+ filter_fn(res).then_some(TypoSuggestion::typo_from_ident(*ident, res))
}));
}
Scope::ToolPrelude => {
suggestions.extend(
this.registered_tools
.iter()
- .map(|ident| TypoSuggestion::typo_from_res(ident.name, res)),
+ .map(|ident| TypoSuggestion::typo_from_ident(*ident, res)),
);
}
Scope::StdLibPrelude => {
Scope::BuiltinTypes => {
suggestions.extend(PrimTy::ALL.iter().filter_map(|prim_ty| {
let res = Res::PrimTy(*prim_ty);
- filter_fn(res).then_some(TypoSuggestion::typo_from_res(prim_ty.name(), res))
+ filter_fn(res)
+ .then_some(TypoSuggestion::typo_from_name(prim_ty.name(), res))
}))
}
}
let a = if built_in.is_empty() { res.article() } else { "a" };
format!("{a}{built_in} {thing}{from}", thing = res.descr())
} else {
- let introduced = if b.is_import() { "imported" } else { "defined" };
+ let introduced = if b.is_import_user_facing() { "imported" } else { "defined" };
format!("the {thing} {introduced} here", thing = res.descr())
}
}
/// If the binding refers to a tuple struct constructor with fields,
/// returns the span of its fields.
fn ctor_fields_span(&self, binding: &NameBinding<'_>) -> Option<Span> {
- if let NameBindingKind::Res(
- Res::Def(DefKind::Ctor(CtorOf::Struct, CtorKind::Fn), ctor_def_id),
- _,
- ) = binding.kind
+ if let NameBindingKind::Res(Res::Def(
+ DefKind::Ctor(CtorOf::Struct, CtorKind::Fn),
+ ctor_def_id,
+ )) = binding.kind
{
let def_id = self.parent(ctor_def_id);
let fields = self.field_names.get(&def_id)?;
next_ident = source;
Some(binding)
}
- ImportKind::Glob { .. } | ImportKind::MacroUse => Some(binding),
+ ImportKind::Glob { .. } | ImportKind::MacroUse | ImportKind::MacroExport => {
+ Some(binding)
+ }
ImportKind::ExternCrate { .. } => None,
},
_ => None,
--- /dev/null
+use crate::{ImportKind, NameBinding, NameBindingKind, Resolver, ResolverTree};
+use rustc_ast::ast;
+use rustc_ast::visit;
+use rustc_ast::visit::Visitor;
+use rustc_ast::Crate;
+use rustc_ast::EnumDef;
+use rustc_data_structures::intern::Interned;
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::def_id::CRATE_DEF_ID;
+use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level};
+use rustc_middle::ty::Visibility;
+
+type ImportId<'a> = Interned<'a, NameBinding<'a>>;
+
+#[derive(Clone, Copy)]
+enum ParentId<'a> {
+ Def(LocalDefId),
+ Import(ImportId<'a>),
+}
+
+impl ParentId<'_> {
+ fn level(self) -> Level {
+ match self {
+ ParentId::Def(_) => Level::Direct,
+ ParentId::Import(_) => Level::Reexported,
+ }
+ }
+}
+
+pub struct EffectiveVisibilitiesVisitor<'r, 'a> {
+ r: &'r mut Resolver<'a>,
+ /// While walking import chains we need to track effective visibilities per-binding, and def id
+ /// keys in `Resolver::effective_visibilities` are not enough for that, because multiple
+ /// bindings can correspond to a single def id in imports. So we keep a separate table.
+ import_effective_visibilities: EffectiveVisibilities<ImportId<'a>>,
+ changed: bool,
+}
+
+impl<'r, 'a> EffectiveVisibilitiesVisitor<'r, 'a> {
+ /// Fills the `Resolver::effective_visibilities` table with public & exported items
+ /// For now, this doesn't resolve macros (FIXME) and cannot resolve Impl, as we
+ /// need access to a TyCtxt for that.
+ pub fn compute_effective_visibilities<'c>(r: &'r mut Resolver<'a>, krate: &'c Crate) {
+ let mut visitor = EffectiveVisibilitiesVisitor {
+ r,
+ import_effective_visibilities: Default::default(),
+ changed: false,
+ };
+
+ visitor.update(CRATE_DEF_ID, CRATE_DEF_ID);
+ visitor.set_bindings_effective_visibilities(CRATE_DEF_ID);
+
+ while visitor.changed {
+ visitor.changed = false;
+ visit::walk_crate(&mut visitor, krate);
+ }
+
+ // Update visibilities for import def ids. These are not used during the
+ // `EffectiveVisibilitiesVisitor` pass, because we have more detailed binding-based
+ // information, but are used by later passes. Effective visibility of an import def id
+ // is the maximum value among visibilities of bindings corresponding to that def id.
+ for (binding, eff_vis) in visitor.import_effective_visibilities.iter() {
+ let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() };
+ if let Some(node_id) = import.id() {
+ let mut update = |node_id| {
+ r.effective_visibilities.update_eff_vis(
+ r.local_def_id(node_id),
+ eff_vis,
+ ResolverTree(&r.definitions, &r.crate_loader),
+ )
+ };
+ update(node_id);
+ if let ImportKind::Single { additional_ids: (id1, id2), .. } = import.kind {
+ // In theory all the single import IDs have individual visibilities and
+ // effective visibilities, but in practice these IDs go straigth to HIR
+ // where all their few uses assume that their (effective) visibility
+ // applies to the whole syntactic `use` item. So they all get the same
+ // value which is the maximum of all bindings. Maybe HIR for imports
+ // shouldn't use three IDs at all.
+ if id1 != ast::DUMMY_NODE_ID {
+ update(id1);
+ }
+ if id2 != ast::DUMMY_NODE_ID {
+ update(id2);
+ }
+ }
+ }
+ }
+
+ info!("resolve::effective_visibilities: {:#?}", r.effective_visibilities);
+ }
+
+ fn nearest_normal_mod(&mut self, def_id: LocalDefId) -> LocalDefId {
+ self.r.get_nearest_non_block_module(def_id.to_def_id()).nearest_parent_mod().expect_local()
+ }
+
+ /// Update effective visibilities of bindings in the given module,
+ /// including their whole reexport chains.
+ fn set_bindings_effective_visibilities(&mut self, module_id: LocalDefId) {
+ assert!(self.r.module_map.contains_key(&&module_id.to_def_id()));
+ let module = self.r.get_module(module_id.to_def_id()).unwrap();
+ let resolutions = self.r.resolutions(module);
+
+ for (_, name_resolution) in resolutions.borrow().iter() {
+ if let Some(mut binding) = name_resolution.borrow().binding() && !binding.is_ambiguity() {
+ // Set the given effective visibility level to `Level::Direct` and
+ // sets the rest of the `use` chain to `Level::Reexported` until
+ // we hit the actual exported item.
+ let mut parent_id = ParentId::Def(module_id);
+ while let NameBindingKind::Import { binding: nested_binding, .. } = binding.kind {
+ let binding_id = ImportId::new_unchecked(binding);
+ self.update_import(binding_id, parent_id);
+
+ parent_id = ParentId::Import(binding_id);
+ binding = nested_binding;
+ }
+
+ if let Some(def_id) = binding.res().opt_def_id().and_then(|id| id.as_local()) {
+ self.update_def(def_id, binding.vis.expect_local(), parent_id);
+ }
+ }
+ }
+ }
+
+ fn effective_vis(&self, parent_id: ParentId<'a>) -> Option<EffectiveVisibility> {
+ match parent_id {
+ ParentId::Def(def_id) => self.r.effective_visibilities.effective_vis(def_id),
+ ParentId::Import(binding) => self.import_effective_visibilities.effective_vis(binding),
+ }
+ .copied()
+ }
+
+ /// The update is guaranteed to not change the table and we can skip it.
+ fn is_noop_update(
+ &self,
+ parent_id: ParentId<'a>,
+ nominal_vis: Visibility,
+ default_vis: Visibility,
+ ) -> bool {
+ nominal_vis == default_vis
+ || match parent_id {
+ ParentId::Def(def_id) => self.r.visibilities[&def_id],
+ ParentId::Import(binding) => binding.vis.expect_local(),
+ } == default_vis
+ }
+
+ fn update_import(&mut self, binding: ImportId<'a>, parent_id: ParentId<'a>) {
+ let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() };
+ let nominal_vis = binding.vis.expect_local();
+ let default_vis = Visibility::Restricted(
+ import
+ .id()
+ .map(|id| self.nearest_normal_mod(self.r.local_def_id(id)))
+ .unwrap_or(CRATE_DEF_ID),
+ );
+ if self.is_noop_update(parent_id, nominal_vis, default_vis) {
+ return;
+ }
+ self.changed |= self.import_effective_visibilities.update(
+ binding,
+ nominal_vis,
+ default_vis,
+ self.effective_vis(parent_id),
+ parent_id.level(),
+ ResolverTree(&self.r.definitions, &self.r.crate_loader),
+ );
+ }
+
+ fn update_def(&mut self, def_id: LocalDefId, nominal_vis: Visibility, parent_id: ParentId<'a>) {
+ let default_vis = Visibility::Restricted(self.nearest_normal_mod(def_id));
+ if self.is_noop_update(parent_id, nominal_vis, default_vis) {
+ return;
+ }
+ self.changed |= self.r.effective_visibilities.update(
+ def_id,
+ nominal_vis,
+ if def_id == CRATE_DEF_ID { Visibility::Public } else { default_vis },
+ self.effective_vis(parent_id),
+ parent_id.level(),
+ ResolverTree(&self.r.definitions, &self.r.crate_loader),
+ );
+ }
+
+ fn update(&mut self, def_id: LocalDefId, parent_id: LocalDefId) {
+ self.update_def(def_id, self.r.visibilities[&def_id], ParentId::Def(parent_id));
+ }
+}
+
+impl<'r, 'ast> Visitor<'ast> for EffectiveVisibilitiesVisitor<'ast, 'r> {
+ fn visit_item(&mut self, item: &'ast ast::Item) {
+ let def_id = self.r.local_def_id(item.id);
+ // Update effective visibilities of nested items.
+ // If it's a mod, also make the visitor walk all of its items
+ match item.kind {
+ // Resolved in rustc_privacy when types are available
+ ast::ItemKind::Impl(..) => return,
+
+ // Should be unreachable at this stage
+ ast::ItemKind::MacCall(..) => panic!(
+ "ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
+ ),
+
+ ast::ItemKind::Mod(..) => {
+ self.set_bindings_effective_visibilities(def_id);
+ visit::walk_item(self, item);
+ }
+
+ ast::ItemKind::Enum(EnumDef { ref variants }, _) => {
+ self.set_bindings_effective_visibilities(def_id);
+ for variant in variants {
+ let variant_def_id = self.r.local_def_id(variant.id);
+ for field in variant.data.fields() {
+ self.update(self.r.local_def_id(field.id), variant_def_id);
+ }
+ }
+ }
+
+ ast::ItemKind::Struct(ref def, _) | ast::ItemKind::Union(ref def, _) => {
+ for field in def.fields() {
+ self.update(self.r.local_def_id(field.id), def_id);
+ }
+ }
+
+ ast::ItemKind::Trait(..) => {
+ self.set_bindings_effective_visibilities(def_id);
+ }
+
+ ast::ItemKind::ExternCrate(..)
+ | ast::ItemKind::Use(..)
+ | ast::ItemKind::Static(..)
+ | ast::ItemKind::Const(..)
+ | ast::ItemKind::GlobalAsm(..)
+ | ast::ItemKind::TyAlias(..)
+ | ast::ItemKind::TraitAlias(..)
+ | ast::ItemKind::MacroDef(..)
+ | ast::ItemKind::ForeignMod(..)
+ | ast::ItemKind::Fn(..) => return,
+ }
+ }
+}
-use rustc_ast::{self as ast, NodeId};
+use rustc_ast as ast;
use rustc_feature::is_builtin_attr_name;
use rustc_hir::def::{DefKind, Namespace, NonMacroAttrKind, PartialRes, PerNS};
use rustc_hir::PrimTy;
use rustc_middle::bug;
use rustc_middle::ty;
-use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK;
-use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_span::def_id::LocalDefId;
use rustc_span::edition::Edition;
use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext};
};
use crate::macros::{sub_namespace_match, MacroRulesScope};
use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize};
-use crate::{ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot};
+use crate::{Import, ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot};
use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res};
use crate::{ResolutionError, Resolver, Scope, ScopeSet, Segment, ToNameBinding, Weak};
};
let mut scope = match ns {
_ if is_absolute_path => Scope::CrateRoot,
- TypeNS | ValueNS => Scope::Module(module, None),
+ TypeNS | ValueNS => Scope::Module(module),
MacroNS => Scope::DeriveHelpers(parent_scope.expansion),
};
let mut ctxt = ctxt.normalize_to_macros_2_0();
MacroRulesScope::Invocation(invoc_id) => {
Scope::MacroRules(self.invocation_parent_scopes[&invoc_id].macro_rules)
}
- MacroRulesScope::Empty => Scope::Module(module, None),
+ MacroRulesScope::Empty => Scope::Module(module),
},
Scope::CrateRoot => match ns {
TypeNS => {
}
ValueNS | MacroNS => break,
},
- Scope::Module(module, prev_lint_id) => {
+ Scope::Module(module) => {
use_prelude = !module.no_implicit_prelude;
- let derive_fallback_lint_id = match scope_set {
- ScopeSet::Late(.., lint_id) => lint_id,
- _ => None,
- };
- match self.hygienic_lexical_parent(module, &mut ctxt, derive_fallback_lint_id) {
- Some((parent_module, lint_id)) => {
- Scope::Module(parent_module, lint_id.or(prev_lint_id))
- }
+ match self.hygienic_lexical_parent(module, &mut ctxt) {
+ Some(parent_module) => Scope::Module(parent_module),
None => {
ctxt.adjust(ExpnId::root());
match ns {
&mut self,
module: Module<'a>,
ctxt: &mut SyntaxContext,
- derive_fallback_lint_id: Option<NodeId>,
- ) -> Option<(Module<'a>, Option<NodeId>)> {
+ ) -> Option<Module<'a>> {
if !module.expansion.outer_expn_is_descendant_of(*ctxt) {
- return Some((self.expn_def_scope(ctxt.remove_mark()), None));
+ return Some(self.expn_def_scope(ctxt.remove_mark()));
}
if let ModuleKind::Block = module.kind {
- return Some((module.parent.unwrap().nearest_item_scope(), None));
- }
-
- // We need to support the next case under a deprecation warning
- // ```
- // struct MyStruct;
- // ---- begin: this comes from a proc macro derive
- // mod implementation_details {
- // // Note that `MyStruct` is not in scope here.
- // impl SomeTrait for MyStruct { ... }
- // }
- // ---- end
- // ```
- // So we have to fall back to the module's parent during lexical resolution in this case.
- if derive_fallback_lint_id.is_some() {
- if let Some(parent) = module.parent {
- // Inner module is inside the macro, parent module is outside of the macro.
- if module.expansion != parent.expansion
- && module.expansion.is_descendant_of(parent.expansion)
- {
- // The macro is a proc macro derive
- if let Some(def_id) = module.expansion.expn_data().macro_def_id {
- let ext = self.get_macro_by_def_id(def_id).ext;
- if ext.builtin_name.is_none()
- && ext.macro_kind() == MacroKind::Derive
- && parent.expansion.outer_expn_is_descendant_of(*ctxt)
- {
- return Some((parent, derive_fallback_lint_id));
- }
- }
- }
- }
+ return Some(module.parent.unwrap().nearest_item_scope());
}
None
Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
}
}
- Scope::Module(module, derive_fallback_lint_id) => {
+ Scope::Module(module) => {
let adjusted_parent_scope = &ParentScope { module, ..*parent_scope };
let binding = this.resolve_ident_in_module_unadjusted_ext(
ModuleOrUniformRoot::Module(module),
);
match binding {
Ok(binding) => {
- if let Some(lint_id) = derive_fallback_lint_id {
- this.lint_buffer.buffer_lint_with_diagnostic(
- PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
- lint_id,
- orig_ident.span,
- &format!(
- "cannot find {} `{}` in this scope",
- ns.descr(),
- ident
- ),
- BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback(
- orig_ident.span,
- ),
- );
- }
let misc_flags = if ptr::eq(module, this.graph_root) {
Flags::MISC_SUGGEST_CRATE
} else if module.is_normal() {
}
if !restricted_shadowing && binding.expansion != LocalExpnId::ROOT {
- if let NameBindingKind::Res(_, true) = binding.kind {
+ if let NameBindingKind::Import {
+ import: Import { kind: ImportKind::MacroExport, .. },
+ ..
+ } = binding.kind
+ {
self.macro_expanded_macro_export_errors.insert((path_span, binding.span));
}
}
type_ns_only: bool,
/// Did this import result from a nested import? ie. `use foo::{bar, baz};`
nested: bool,
+ /// The ID of the `UseTree` that imported this `Import`.
+ ///
+ /// In the case where the `Import` was expanded from a "nested" use tree,
+ /// this id is the ID of the leaf tree. For example:
+ ///
+ /// ```ignore (pacify the merciless tidy)
+ /// use foo::bar::{a, b}
+ /// ```
+ ///
+ /// If this is the import for `foo::bar::a`, we would have the ID of the `UseTree`
+ /// for `a` in this field.
+ id: NodeId,
/// Additional `NodeId`s allocated to a `ast::UseTree` for automatically generated `use` statement
/// (eg. implicit struct constructors)
additional_ids: (NodeId, NodeId),
},
Glob {
is_prelude: bool,
- max_vis: Cell<Option<ty::Visibility>>, // The visibility of the greatest re-export.
- // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors.
+ // The visibility of the greatest re-export.
+ // n.b. `max_vis` is only used in `finalize_import` to check for re-export errors.
+ max_vis: Cell<Option<ty::Visibility>>,
+ id: NodeId,
},
ExternCrate {
source: Option<Symbol>,
target: Ident,
+ id: NodeId,
},
MacroUse,
+ MacroExport,
}
/// Manually implement `Debug` for `ImportKind` because the `source/target_bindings`
ref target,
ref type_ns_only,
ref nested,
+ ref id,
ref additional_ids,
// Ignore the following to avoid an infinite loop while printing.
source_bindings: _,
.field("target", target)
.field("type_ns_only", type_ns_only)
.field("nested", nested)
+ .field("id", id)
.field("additional_ids", additional_ids)
.finish_non_exhaustive(),
- Glob { ref is_prelude, ref max_vis } => f
+ Glob { ref is_prelude, ref max_vis, ref id } => f
.debug_struct("Glob")
.field("is_prelude", is_prelude)
.field("max_vis", max_vis)
+ .field("id", id)
.finish(),
- ExternCrate { ref source, ref target } => f
+ ExternCrate { ref source, ref target, ref id } => f
.debug_struct("ExternCrate")
.field("source", source)
.field("target", target)
+ .field("id", id)
.finish(),
MacroUse => f.debug_struct("MacroUse").finish(),
+ MacroExport => f.debug_struct("MacroExport").finish(),
}
}
}
pub(crate) struct Import<'a> {
pub kind: ImportKind<'a>,
- /// The ID of the `extern crate`, `UseTree` etc that imported this `Import`.
- ///
- /// In the case where the `Import` was expanded from a "nested" use tree,
- /// this id is the ID of the leaf tree. For example:
- ///
- /// ```ignore (pacify the merciless tidy)
+ /// Node ID of the "root" use item -- this is always the same as `ImportKind`'s `id`
+ /// (if it exists) except in the case of "nested" use trees, in which case
+ /// it will be the ID of the root use tree. e.g., in the example
+ /// ```ignore (incomplete code)
/// use foo::bar::{a, b}
/// ```
- ///
- /// If this is the import for `foo::bar::a`, we would have the ID of the `UseTree`
- /// for `a` in this field.
- pub id: NodeId,
-
- /// The `id` of the "root" use-kind -- this is always the same as
- /// `id` except in the case of "nested" use trees, in which case
- /// it will be the `id` of the root use tree. e.g., in the example
- /// from `id`, this would be the ID of the `use foo::bar`
- /// `UseTree` node.
+ /// this would be the ID of the `use foo::bar` `UseTree` node.
+ /// In case of imports without their own node ID it's the closest node that can be used,
+ /// for example, for reporting lints.
pub root_id: NodeId,
/// Span of the entire use statement.
pub(crate) fn expect_vis(&self) -> ty::Visibility {
self.vis.get().expect("encountered cleared import visibility")
}
+
+ pub(crate) fn id(&self) -> Option<NodeId> {
+ match self.kind {
+ ImportKind::Single { id, .. }
+ | ImportKind::Glob { id, .. }
+ | ImportKind::ExternCrate { id, .. } => Some(id),
+ ImportKind::MacroUse | ImportKind::MacroExport => None,
+ }
+ }
}
/// Records information about the resolution of a name in a namespace of a module.
self.record_use(target, dummy_binding, false);
} else if import.imported_module.get().is_none() {
import.used.set(true);
- self.used_imports.insert(import.id);
+ if let Some(id) = import.id() {
+ self.used_imports.insert(id);
+ }
}
}
}
{
// In the case of a new import line, throw a diagnostic message
// for the previous line.
- self.throw_unresolved_import_error(errors, None);
+ self.throw_unresolved_import_error(errors);
errors = vec![];
}
if seen_spans.insert(err.span) {
}
if !errors.is_empty() {
- self.throw_unresolved_import_error(errors, None);
+ self.throw_unresolved_import_error(errors);
}
}
- fn throw_unresolved_import_error(
- &self,
- errors: Vec<(String, UnresolvedImportError)>,
- span: Option<MultiSpan>,
- ) {
+ fn throw_unresolved_import_error(&self, errors: Vec<(String, UnresolvedImportError)>) {
+ if errors.is_empty() {
+ return;
+ }
+
/// Upper limit on the number of `span_label` messages.
const MAX_LABEL_COUNT: usize = 10;
- let (span, msg) = if errors.is_empty() {
- (span.unwrap(), "unresolved import".to_string())
- } else {
- let span = MultiSpan::from_spans(errors.iter().map(|(_, err)| err.span).collect());
-
- let paths = errors.iter().map(|(path, _)| format!("`{}`", path)).collect::<Vec<_>>();
-
- let msg = format!("unresolved import{} {}", pluralize!(paths.len()), paths.join(", "),);
-
- (span, msg)
- };
+ let span = MultiSpan::from_spans(errors.iter().map(|(_, err)| err.span).collect());
+ let paths = errors.iter().map(|(path, _)| format!("`{}`", path)).collect::<Vec<_>>();
+ let msg = format!("unresolved import{} {}", pluralize!(paths.len()), paths.join(", "),);
let mut diag = struct_span_err!(self.r.session, span, E0432, "{}", &msg);
PathResult::Indeterminate => unreachable!(),
};
- let (ident, target, source_bindings, target_bindings, type_ns_only) = match import.kind {
- ImportKind::Single {
- source,
- target,
- ref source_bindings,
- ref target_bindings,
- type_ns_only,
- ..
- } => (source, target, source_bindings, target_bindings, type_ns_only),
- ImportKind::Glob { is_prelude, ref max_vis } => {
- if import.module_path.len() <= 1 {
- // HACK(eddyb) `lint_if_path_starts_with_module` needs at least
- // 2 segments, so the `resolve_path` above won't trigger it.
- let mut full_path = import.module_path.clone();
- full_path.push(Segment::from_ident(Ident::empty()));
- self.r.lint_if_path_starts_with_module(Some(finalize), &full_path, None);
- }
+ let (ident, target, source_bindings, target_bindings, type_ns_only, import_id) =
+ match import.kind {
+ ImportKind::Single {
+ source,
+ target,
+ ref source_bindings,
+ ref target_bindings,
+ type_ns_only,
+ id,
+ ..
+ } => (source, target, source_bindings, target_bindings, type_ns_only, id),
+ ImportKind::Glob { is_prelude, ref max_vis, id } => {
+ if import.module_path.len() <= 1 {
+ // HACK(eddyb) `lint_if_path_starts_with_module` needs at least
+ // 2 segments, so the `resolve_path` above won't trigger it.
+ let mut full_path = import.module_path.clone();
+ full_path.push(Segment::from_ident(Ident::empty()));
+ self.r.lint_if_path_starts_with_module(Some(finalize), &full_path, None);
+ }
- if let ModuleOrUniformRoot::Module(module) = module {
- if ptr::eq(module, import.parent_scope.module) {
- // Importing a module into itself is not allowed.
- return Some(UnresolvedImportError {
- span: import.span,
- label: Some(String::from("cannot glob-import a module into itself")),
- note: None,
- suggestion: None,
- candidate: None,
- });
+ if let ModuleOrUniformRoot::Module(module) = module {
+ if ptr::eq(module, import.parent_scope.module) {
+ // Importing a module into itself is not allowed.
+ return Some(UnresolvedImportError {
+ span: import.span,
+ label: Some(String::from(
+ "cannot glob-import a module into itself",
+ )),
+ note: None,
+ suggestion: None,
+ candidate: None,
+ });
+ }
}
- }
- if !is_prelude
+ if !is_prelude
&& let Some(max_vis) = max_vis.get()
&& !max_vis.is_at_least(import.expect_vis(), &*self.r)
{
let msg = "glob import doesn't reexport anything because no candidate is public enough";
- self.r.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.id, import.span, msg);
+ self.r.lint_buffer.buffer_lint(UNUSED_IMPORTS, id, import.span, msg);
}
- return None;
- }
- _ => unreachable!(),
- };
+ return None;
+ }
+ _ => unreachable!(),
+ };
let mut all_ns_err = true;
self.r.per_ns(|this, ns| {
match binding.kind {
// Never suggest the name that has binding error
// i.e., the name that cannot be previously resolved
- NameBindingKind::Res(Res::Err, _) => None,
+ NameBindingKind::Res(Res::Err) => None,
_ => Some(i.name),
}
}
);
self.r.lint_buffer.buffer_lint(
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
- import.id,
+ import_id,
import.span,
&msg,
);
let mut err =
struct_span_err!(self.r.session, import.span, E0364, "{error_msg}");
match binding.kind {
- NameBindingKind::Res(Res::Def(DefKind::Macro(_), def_id), _)
+ NameBindingKind::Res(Res::Def(DefKind::Macro(_), def_id))
// exclude decl_macro
if self.r.get_macro_by_def_id(def_id).macro_rules =>
{
// purposes it's good enough to just favor one over the other.
self.r.per_ns(|this, ns| {
if let Ok(binding) = source_bindings[ns].get() {
- this.import_res_map.entry(import.id).or_default()[ns] = Some(binding.res());
+ this.import_res_map.entry(import_id).or_default()[ns] = Some(binding.res());
}
});
target_bindings: &PerNS<Cell<Option<&'b NameBinding<'b>>>>,
target: Ident,
) {
+ // This function is only called for single imports.
+ let ImportKind::Single { id, .. } = import.kind else { unreachable!() };
+
// Skip if the import was produced by a macro.
if import.parent_scope.expansion != LocalExpnId::ROOT {
return;
redundant_spans.dedup();
self.r.lint_buffer.buffer_lint_with_diagnostic(
UNUSED_IMPORTS,
- import.id,
+ id,
import.span,
&format!("the item `{}` is imported redundantly", ident),
BuiltinLintDiagnostics::RedundantImport(redundant_spans, ident),
}
fn resolve_glob_import(&mut self, import: &'b Import<'b>) {
+ // This function is only called for glob imports.
+ let ImportKind::Glob { id, is_prelude, .. } = import.kind else { unreachable!() };
+
let ModuleOrUniformRoot::Module(module) = import.imported_module.get().unwrap() else {
self.r.session.span_err(import.span, "cannot glob-import all possible crates");
return;
return;
} else if ptr::eq(module, import.parent_scope.module) {
return;
- } else if let ImportKind::Glob { is_prelude: true, .. } = import.kind {
+ } else if is_prelude {
self.r.prelude = Some(module);
return;
}
}
// Record the destination of this import
- self.r.record_partial_res(import.id, PartialRes::new(module.res().unwrap()));
+ self.r.record_partial_res(id, PartialRes::new(module.res().unwrap()));
}
// Miscellaneous post-processing, including recording re-exports,
ImportKind::Glob { .. } => "*".to_string(),
ImportKind::ExternCrate { .. } => "<extern crate>".to_string(),
ImportKind::MacroUse => "#[macro_use]".to_string(),
+ ImportKind::MacroExport => "#[macro_export]".to_string(),
}
}
use smallvec::{smallvec, SmallVec};
use rustc_span::source_map::{respan, Spanned};
+use std::assert_matches::debug_assert_matches;
use std::collections::{hash_map::Entry, BTreeSet};
-use std::mem::{replace, take};
+use std::mem::{replace, swap, take};
mod diagnostics;
/// They will be used to determine the correct lifetime for the fn return type.
/// The `LifetimeElisionCandidate` is used for diagnostics, to suggest introducing named
/// lifetimes.
- lifetime_elision_candidates: Option<FxIndexMap<LifetimeRes, LifetimeElisionCandidate>>,
+ lifetime_elision_candidates: Option<Vec<(LifetimeRes, LifetimeElisionCandidate)>>,
/// The trait that the current context can refer to.
current_trait_ref: Option<(Module<'a>, TraitRef)>,
match res {
LifetimeRes::Param { .. } | LifetimeRes::Fresh { .. } | LifetimeRes::Static => {
if let Some(ref mut candidates) = self.lifetime_elision_candidates {
- candidates.insert(res, candidate);
+ candidates.push((res, candidate));
}
}
LifetimeRes::Infer | LifetimeRes::Error | LifetimeRes::ElidedAnchor { .. } => {}
has_self: bool,
inputs: impl Iterator<Item = (Option<&'ast Pat>, &'ast Ty)>,
) -> Result<LifetimeRes, (Vec<MissingLifetime>, Vec<ElisionFnParameter>)> {
- let outer_candidates =
- replace(&mut self.lifetime_elision_candidates, Some(Default::default()));
+ enum Elision {
+ /// We have not found any candidate.
+ None,
+ /// We have a candidate bound to `self`.
+ Self_(LifetimeRes),
+ /// We have a candidate bound to a parameter.
+ Param(LifetimeRes),
+ /// We failed elision.
+ Err,
+ }
- let mut elision_lifetime = None;
- let mut lifetime_count = 0;
+ // Save elision state to reinstate it later.
+ let outer_candidates = self.lifetime_elision_candidates.take();
+
+ // Result of elision.
+ let mut elision_lifetime = Elision::None;
+ // Information for diagnostics.
let mut parameter_info = Vec::new();
+ let mut all_candidates = Vec::new();
let mut bindings = smallvec![(PatBoundCtx::Product, Default::default())];
for (index, (pat, ty)) in inputs.enumerate() {
this.resolve_pattern(pat, PatternSource::FnParam, &mut bindings);
}
});
+
+ // Record elision candidates only for this parameter.
+ debug_assert_matches!(self.lifetime_elision_candidates, None);
+ self.lifetime_elision_candidates = Some(Default::default());
self.visit_ty(ty);
+ let local_candidates = self.lifetime_elision_candidates.take();
- if let Some(ref candidates) = self.lifetime_elision_candidates {
- let new_count = candidates.len();
- let local_count = new_count - lifetime_count;
- if local_count != 0 {
+ if let Some(candidates) = local_candidates {
+ let distinct: FxHashSet<_> = candidates.iter().map(|(res, _)| *res).collect();
+ let lifetime_count = distinct.len();
+ if lifetime_count != 0 {
parameter_info.push(ElisionFnParameter {
index,
ident: if let Some(pat) = pat && let PatKind::Ident(_, ident, _) = pat.kind {
} else {
None
},
- lifetime_count: local_count,
+ lifetime_count,
span: ty.span,
});
+ all_candidates.extend(candidates.into_iter().filter_map(|(_, candidate)| {
+ match candidate {
+ LifetimeElisionCandidate::Ignore | LifetimeElisionCandidate::Named => {
+ None
+ }
+ LifetimeElisionCandidate::Missing(missing) => Some(missing),
+ }
+ }));
+ }
+ let mut distinct_iter = distinct.into_iter();
+ if let Some(res) = distinct_iter.next() {
+ match elision_lifetime {
+ // We are the first parameter to bind lifetimes.
+ Elision::None => {
+ if distinct_iter.next().is_none() {
+ // We have a single lifetime => success.
+ elision_lifetime = Elision::Param(res)
+ } else {
+ // We have have multiple lifetimes => error.
+ elision_lifetime = Elision::Err;
+ }
+ }
+ // We have 2 parameters that bind lifetimes => error.
+ Elision::Param(_) => elision_lifetime = Elision::Err,
+ // `self` elision takes precedence over everything else.
+ Elision::Self_(_) | Elision::Err => {}
+ }
}
- lifetime_count = new_count;
}
// Handle `self` specially.
if index == 0 && has_self {
let self_lifetime = self.find_lifetime_for_self(ty);
if let Set1::One(lifetime) = self_lifetime {
- elision_lifetime = Some(lifetime);
- self.lifetime_elision_candidates = None;
+ // We found `self` elision.
+ elision_lifetime = Elision::Self_(lifetime);
} else {
- self.lifetime_elision_candidates = Some(Default::default());
- lifetime_count = 0;
+ // We do not have `self` elision: disregard the `Elision::Param` that we may
+ // have found.
+ elision_lifetime = Elision::None;
}
}
debug!("(resolving function / closure) recorded parameter");
}
- let all_candidates = replace(&mut self.lifetime_elision_candidates, outer_candidates);
- debug!(?all_candidates);
+ // Reinstate elision state.
+ debug_assert_matches!(self.lifetime_elision_candidates, None);
+ self.lifetime_elision_candidates = outer_candidates;
- if let Some(res) = elision_lifetime {
+ if let Elision::Param(res) | Elision::Self_(res) = elision_lifetime {
return Ok(res);
}
- // We do not have a `self` candidate, look at the full list.
- let all_candidates = all_candidates.unwrap();
- if all_candidates.len() == 1 {
- Ok(*all_candidates.first().unwrap().0)
- } else {
- let all_candidates = all_candidates
- .into_iter()
- .filter_map(|(_, candidate)| match candidate {
- LifetimeElisionCandidate::Ignore | LifetimeElisionCandidate::Named => None,
- LifetimeElisionCandidate::Missing(missing) => Some(missing),
- })
- .collect();
- Err((all_candidates, parameter_info))
- }
+ // We do not have a candidate.
+ Err((all_candidates, parameter_info))
}
/// List all the lifetimes that appear in the provided type.
// Do not account for the parameters we just bound for function lifetime elision.
if let Some(ref mut candidates) = self.lifetime_elision_candidates {
for (_, res) in function_lifetime_rib.bindings.values() {
- candidates.remove(res);
+ candidates.retain(|(r, _)| r != res);
}
}
let (mut err, candidates) =
this.smart_resolve_report_errors(path, path_span, PathSource::Type, None);
- if candidates.is_empty() {
- err.cancel();
- return Some(parent_err);
- }
-
// There are two different error messages user might receive at
// this point:
// - E0412 cannot find type `{}` in this scope
// latter one - for paths in expression-position.
//
// Thus (since we're in expression-position at this point), not to
- // confuse the user, we want to keep the *message* from E0432 (so
+ // confuse the user, we want to keep the *message* from E0433 (so
// `parent_err`), but we want *hints* from E0412 (so `err`).
//
// And that's what happens below - we're just mixing both messages
// into a single one.
let mut parent_err = this.r.into_struct_error(parent_err.span, parent_err.node);
+ // overwrite all properties with the parent's error message
err.message = take(&mut parent_err.message);
err.code = take(&mut parent_err.code);
+ swap(&mut err.span, &mut parent_err.span);
err.children = take(&mut parent_err.children);
+ err.sort_span = parent_err.sort_span;
+ err.is_lint = parent_err.is_lint;
+
+ // merge the parent's suggestions with the typo suggestions
+ fn append_result<T, E>(res1: &mut Result<Vec<T>, E>, res2: Result<Vec<T>, E>) {
+ match res1 {
+ Ok(vec1) => match res2 {
+ Ok(mut vec2) => vec1.append(&mut vec2),
+ Err(e) => *res1 = Err(e),
+ },
+ Err(_) => (),
+ };
+ }
+ append_result(&mut err.suggestions, parent_err.suggestions.clone());
parent_err.cancel();
let def_id = this.parent_scope.module.nearest_parent_mod();
if this.should_report_errs() {
- this.r.use_injections.push(UseError {
- err,
- candidates,
- def_id,
- instead: false,
- suggestion: None,
- path: path.into(),
- is_call: source.is_call(),
- });
+ if candidates.is_empty() {
+ // When there is no suggested imports, we can just emit the error
+ // and suggestions immediately. Note that we bypass the usually error
+ // reporting routine (ie via `self.r.report_error`) because we need
+ // to post-process the `ResolutionError` above.
+ err.emit();
+ } else {
+ // If there are suggested imports, the error reporting is delayed
+ this.r.use_injections.push(UseError {
+ err,
+ candidates,
+ def_id,
+ instead: false,
+ suggestion: None,
+ path: path.into(),
+ is_call: source.is_call(),
+ });
+ }
} else {
err.cancel();
}
// We don't return `Some(parent_err)` here, because the error will
- // be already printed as part of the `use` injections
+ // be already printed either immediately or as part of the `use` injections
None
};
#[derive(Debug)]
enum TypoCandidate {
Typo(TypoSuggestion),
- Shadowed(Res),
+ Shadowed(Res, Option<Span>),
None,
}
fn to_opt_suggestion(self) -> Option<TypoSuggestion> {
match self {
TypoCandidate::Typo(sugg) => Some(sugg),
- TypoCandidate::Shadowed(_) | TypoCandidate::None => None,
+ TypoCandidate::Shadowed(_, _) | TypoCandidate::None => None,
}
}
}
}
self.suggest_bare_struct_literal(&mut err);
- self.suggest_pattern_match_with_let(&mut err, source, span);
+
+ if self.suggest_pattern_match_with_let(&mut err, source, span) {
+ // Fallback label.
+ err.span_label(base_error.span, &base_error.fallback_label);
+ return (err, Vec::new());
+ }
self.suggest_self_or_self_ref(&mut err, path, span);
self.detect_assoct_type_constraint_meant_as_path(&mut err, &base_error);
if !self.type_ascription_suggestion(&mut err, base_error.span) {
let mut fallback =
self.suggest_trait_and_bounds(&mut err, source, res, span, &base_error);
+
+ // if we have suggested using pattern matching, then don't add needless suggestions
+ // for typos.
fallback |= self.suggest_typo(&mut err, source, path, span, &base_error);
+
if fallback {
// Fallback label.
err.span_label(base_error.span, &base_error.fallback_label);
let is_expected = &|res| source.is_expected(res);
let ident_span = path.last().map_or(span, |ident| ident.ident.span);
let typo_sugg = self.lookup_typo_candidate(path, source.namespace(), is_expected);
- if let TypoCandidate::Shadowed(res) = typo_sugg
- && let Some(id) = res.opt_def_id()
- && let Some(sugg_span) = self.r.opt_span(id)
+ let is_in_same_file = &|sp1, sp2| {
+ let source_map = self.r.session.source_map();
+ let file1 = source_map.span_to_filename(sp1);
+ let file2 = source_map.span_to_filename(sp2);
+ file1 == file2
+ };
+ // print 'you might have meant' if the candidate is (1) is a shadowed name with
+ // accessible definition and (2) either defined in the same crate as the typo
+ // (could be in a different file) or introduced in the same file as the typo
+ // (could belong to a different crate)
+ if let TypoCandidate::Shadowed(res, Some(sugg_span)) = typo_sugg
+ && res
+ .opt_def_id()
+ .map_or(false, |id| id.is_local() || is_in_same_file(span, sugg_span))
{
err.span_label(
sugg_span,
return false;
}
err.code(rustc_errors::error_code!(E0411));
- err.span_label(
- span,
- "`Self` is only available in impls, traits, and type definitions".to_string(),
- );
+ err.span_label(span, "`Self` is only available in impls, traits, and type definitions");
if let Some(item_kind) = self.diagnostic_metadata.current_item {
err.span_label(
item_kind.ident.span,
err: &mut Diagnostic,
source: PathSource<'_>,
span: Span,
- ) {
+ ) -> bool {
if let PathSource::Expr(_) = source &&
let Some(Expr {
span: expr_span,
"let ",
Applicability::MaybeIncorrect,
);
+ return true;
}
}
+ false
}
fn get_single_associated_item(
.collect();
if targets.len() == 1 {
let target = targets[0];
- return Some(TypoSuggestion::single_item_from_res(
- target.0.ident.name,
- target.1,
- ));
+ return Some(TypoSuggestion::single_item_from_ident(target.0.ident, target.1));
}
}
}
// Locals and type parameters
for (ident, &res) in &rib.bindings {
if filter_fn(res) && ident.span.ctxt() == rib_ctxt {
- names.push(TypoSuggestion::typo_from_res(ident.name, res));
+ names.push(TypoSuggestion::typo_from_ident(*ident, res));
}
}
Res::Def(DefKind::Mod, crate_id.as_def_id());
if filter_fn(crate_mod) {
- Some(TypoSuggestion::typo_from_res(
- ident.name, crate_mod,
- ))
+ Some(TypoSuggestion::typo_from_ident(*ident, crate_mod))
} else {
None
}
// Add primitive types to the mix
if filter_fn(Res::PrimTy(PrimTy::Bool)) {
names.extend(PrimTy::ALL.iter().map(|prim_ty| {
- TypoSuggestion::typo_from_res(prim_ty.name(), Res::PrimTy(*prim_ty))
+ TypoSuggestion::typo_from_name(prim_ty.name(), Res::PrimTy(*prim_ty))
}))
}
} else {
return TypoCandidate::None;
};
if found == name {
- TypoCandidate::Shadowed(sugg.res)
+ TypoCandidate::Shadowed(sugg.res, sugg.span)
} else {
TypoCandidate::Typo(sugg)
}
//! Type-relative name resolution (methods, fields, associated items) happens in `rustc_hir_analysis`.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(assert_matches)]
#![feature(box_patterns)]
#![feature(drain_filter)]
#![feature(if_let_guard)]
use rustc_index::vec::IndexVec;
use rustc_metadata::creader::{CStore, CrateLoader};
use rustc_middle::metadata::ModChild;
-use rustc_middle::middle::privacy::AccessLevels;
+use rustc_middle::middle::privacy::EffectiveVisibilities;
use rustc_middle::span_bug;
use rustc_middle::ty::{self, DefIdTree, MainDefinition, RegisteredTools};
use rustc_middle::ty::{ResolverGlobalCtxt, ResolverOutputs};
use late::{HasGenericParams, PathSource, PatternSource};
use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
-use crate::access_levels::AccessLevelsVisitor;
+use crate::effective_visibilities::EffectiveVisibilitiesVisitor;
type Res = def::Res<NodeId>;
-mod access_levels;
mod build_reduced_graph;
mod check_unused;
mod def_collector;
mod diagnostics;
+mod effective_visibilities;
mod ident;
mod imports;
mod late;
DeriveHelpersCompat,
MacroRules(MacroRulesScopeRef<'a>),
CrateRoot,
- // The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK`
- // lint if it should be reported.
- Module(Module<'a>, Option<NodeId>),
+ Module(Module<'a>),
MacroUsePrelude,
BuiltinAttrs,
ExternPrelude,
#[derive(Clone, Debug)]
enum NameBindingKind<'a> {
- Res(Res, /* is_macro_export */ bool),
+ Res(Res),
Module(Module<'a>),
Import { binding: &'a NameBinding<'a>, import: &'a Import<'a>, used: Cell<bool> },
}
fn res(&self) -> Res {
match self.kind {
- NameBindingKind::Res(res, _) => res,
+ NameBindingKind::Res(res) => res,
NameBindingKind::Module(module) => module.res().unwrap(),
NameBindingKind::Import { binding, .. } => binding.res(),
}
fn is_possibly_imported_variant(&self) -> bool {
match self.kind {
NameBindingKind::Import { binding, .. } => binding.is_possibly_imported_variant(),
- NameBindingKind::Res(
- Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), _),
+ NameBindingKind::Res(Res::Def(
+ DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..),
_,
- ) => true,
+ )) => true,
NameBindingKind::Res(..) | NameBindingKind::Module(..) => false,
}
}
matches!(self.kind, NameBindingKind::Import { .. })
}
+ /// The binding introduced by `#[macro_export] macro_rules` is a public import, but it might
+ /// not be perceived as such by users, so treat it as a non-import in some diagnostics.
+ fn is_import_user_facing(&self) -> bool {
+ matches!(self.kind, NameBindingKind::Import { import, .. }
+ if !matches!(import.kind, ImportKind::MacroExport))
+ }
+
fn is_glob_import(&self) -> bool {
match self.kind {
NameBindingKind::Import { import, .. } => import.is_glob(),
proc_macros: Vec<NodeId>,
confused_type_with_std_module: FxHashMap<Span, Span>,
- access_levels: AccessLevels,
+ effective_visibilities: EffectiveVisibilities,
}
/// Nothing really interesting here; it just provides memory for the rest of the crate.
}
}
-impl<'a, 'b> DefIdTree for &'a Resolver<'b> {
+/// A minimal subset of resolver that can implemenent `DefIdTree`, sometimes
+/// required to satisfy borrow checker by avoiding borrowing the whole resolver.
+#[derive(Clone, Copy)]
+struct ResolverTree<'a, 'b>(&'a Definitions, &'a CrateLoader<'b>);
+
+impl DefIdTree for ResolverTree<'_, '_> {
#[inline]
fn opt_parent(self, id: DefId) -> Option<DefId> {
+ let ResolverTree(definitions, crate_loader) = self;
match id.as_local() {
- Some(id) => self.definitions.def_key(id).parent,
- None => self.cstore().def_key(id).parent,
+ Some(id) => definitions.def_key(id).parent,
+ None => crate_loader.cstore().def_key(id).parent,
}
.map(|index| DefId { index, ..id })
}
}
+impl<'a, 'b> DefIdTree for &'a Resolver<'b> {
+ #[inline]
+ fn opt_parent(self, id: DefId) -> Option<DefId> {
+ ResolverTree(&self.definitions, &self.crate_loader).opt_parent(id)
+ }
+}
+
impl Resolver<'_> {
fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> {
self.node_id_to_def_id.get(&node).copied()
arenas,
dummy_binding: arenas.alloc_name_binding(NameBinding {
- kind: NameBindingKind::Res(Res::Err, false),
+ kind: NameBindingKind::Res(Res::Err),
ambiguity: None,
expansion: LocalExpnId::ROOT,
span: DUMMY_SP,
trait_impls: Default::default(),
proc_macros: Default::default(),
confused_type_with_std_module: Default::default(),
- access_levels: Default::default(),
+ effective_visibilities: Default::default(),
};
let root_parent_scope = ParentScope::module(graph_root, &resolver);
let glob_map = self.glob_map;
let main_def = self.main_def;
let confused_type_with_std_module = self.confused_type_with_std_module;
- let access_levels = self.access_levels;
+ let effective_visibilities = self.effective_visibilities;
let global_ctxt = ResolverGlobalCtxt {
cstore,
source_span,
expn_that_defined,
visibilities,
has_pub_restricted,
- access_levels,
+ effective_visibilities,
extern_crate_map,
reexport_map,
glob_map,
proc_macros,
confused_type_with_std_module: self.confused_type_with_std_module.clone(),
registered_tools: self.registered_tools.clone(),
- access_levels: self.access_levels.clone(),
+ effective_visibilities: self.effective_visibilities.clone(),
};
let ast_lowering = ty::ResolverAstLowering {
legacy_const_generic_args: self.legacy_const_generic_args.clone(),
pub fn resolve_crate(&mut self, krate: &Crate) {
self.session.time("resolve_crate", || {
self.session.time("finalize_imports", || ImportResolver { r: self }.finalize_imports());
- self.session.time("resolve_access_levels", || {
- AccessLevelsVisitor::compute_access_levels(self, krate)
+ self.session.time("compute_effective_visibilities", || {
+ EffectiveVisibilitiesVisitor::compute_effective_visibilities(self, krate)
});
self.session.time("finalize_macro_resolutions", || self.finalize_macro_resolutions());
self.session.time("late_resolve_crate", || self.late_resolve_crate(krate));
self.visit_scopes(ScopeSet::All(TypeNS, false), parent_scope, ctxt, |this, scope, _, _| {
match scope {
- Scope::Module(module, _) => {
+ Scope::Module(module) => {
this.traits_in_module(module, assoc_item, &mut found_traits);
}
Scope::StdLibPrelude => {
) -> SmallVec<[LocalDefId; 1]> {
let mut import_ids = smallvec![];
while let NameBindingKind::Import { import, binding, .. } = kind {
- let id = self.local_def_id(import.id);
- self.maybe_unused_trait_imports.insert(id);
+ if let Some(node_id) = import.id() {
+ let def_id = self.local_def_id(node_id);
+ self.maybe_unused_trait_imports.insert(def_id);
+ import_ids.push(def_id);
+ }
self.add_to_glob_map(&import, trait_name);
- import_ids.push(id);
kind = &binding.kind;
}
import_ids
}
used.set(true);
import.used.set(true);
- self.used_imports.insert(import.id);
+ if let Some(id) = import.id() {
+ self.used_imports.insert(id);
+ }
self.add_to_glob_map(&import, ident);
self.record_use(ident, binding, false);
}
#[inline]
fn add_to_glob_map(&mut self, import: &Import<'_>, ident: Ident) {
- if import.is_glob() {
- let def_id = self.local_def_id(import.id);
+ if let ImportKind::Glob { id, .. } = import.kind {
+ let def_id = self.local_def_id(id);
self.glob_map.entry(def_id).or_default().insert(ident.name);
}
}
// Items that go to reexport table encoded to metadata and visible through it to other crates.
fn is_reexport(&self, binding: &NameBinding<'a>) -> Option<def::Res<!>> {
- // FIXME: Consider changing the binding inserted by `#[macro_export] macro_rules`
- // into the crate root to actual `NameBindingKind::Import`.
- if binding.is_import()
- || matches!(binding.kind, NameBindingKind::Res(_, _is_macro_export @ true))
- {
+ if binding.is_import() {
let res = binding.res().expect_non_local();
// Ambiguous imports are treated as errors at this point and are
// not exposed to other crates (see #36837 for more details).
($save_ctxt:expr, $id:expr) => {
Access {
public: $save_ctxt.tcx.visibility($id).is_public(),
- reachable: $save_ctxt.access_levels.is_reachable($id),
+ reachable: $save_ctxt.effective_visibilities.is_reachable($id),
}
};
}
body: hir::BodyId,
) {
let map = self.tcx.hir();
- self.nest_typeck_results(item.def_id.def_id, |v| {
+ self.nest_typeck_results(item.owner_id.def_id, |v| {
let body = map.body(body);
if let Some(fn_data) = v.save_ctxt.get_item_data(item) {
down_cast_data!(fn_data, DefData, item.span);
v.process_formals(body.params, &fn_data.qualname);
v.process_generic_params(ty_params, &fn_data.qualname, item.hir_id());
- v.dumper.dump_def(&access_from!(v.save_ctxt, item.def_id.def_id), fn_data);
+ v.dumper.dump_def(&access_from!(v.save_ctxt, item.owner_id.def_id), fn_data);
}
for arg in decl.inputs {
typ: &'tcx hir::Ty<'tcx>,
expr: &'tcx hir::Expr<'tcx>,
) {
- self.nest_typeck_results(item.def_id.def_id, |v| {
+ self.nest_typeck_results(item.owner_id.def_id, |v| {
if let Some(var_data) = v.save_ctxt.get_item_data(item) {
down_cast_data!(var_data, DefData, item.span);
- v.dumper.dump_def(&access_from!(v.save_ctxt, item.def_id.def_id), var_data);
+ v.dumper.dump_def(&access_from!(v.save_ctxt, item.owner_id.def_id), var_data);
}
v.visit_ty(&typ);
v.visit_expr(expr);
) {
debug!("process_struct {:?} {:?}", item, item.span);
let name = item.ident.to_string();
- let qualname = format!("::{}", self.tcx.def_path_str(item.def_id.to_def_id()));
+ let qualname = format!("::{}", self.tcx.def_path_str(item.owner_id.to_def_id()));
let kind = match item.kind {
hir::ItemKind::Struct(_, _) => DefKind::Struct,
let span = self.span_from_span(item.ident.span);
let attrs = self.tcx.hir().attrs(item.hir_id());
self.dumper.dump_def(
- &access_from!(self.save_ctxt, item.def_id.def_id),
+ &access_from!(self.save_ctxt, item.owner_id.def_id),
Def {
kind,
- id: id_from_def_id(item.def_id.to_def_id()),
+ id: id_from_def_id(item.owner_id.to_def_id()),
span,
name,
qualname: qualname.clone(),
);
}
- self.nest_typeck_results(item.def_id.def_id, |v| {
+ self.nest_typeck_results(item.owner_id.def_id, |v| {
for field in def.fields() {
v.process_struct_field_def(field, item.hir_id());
v.visit_ty(&field.ty);
};
down_cast_data!(enum_data, DefData, item.span);
- let access = access_from!(self.save_ctxt, item.def_id.def_id);
+ let access = access_from!(self.save_ctxt, item.owner_id.def_id);
for variant in enum_definition.variants {
let name = variant.ident.name.to_string();
if !self.span.filter_generated(name_span) {
let span = self.span_from_span(name_span);
let id = id_from_hir_id(variant.id, &self.save_ctxt);
- let parent = Some(id_from_def_id(item.def_id.to_def_id()));
+ let parent = Some(id_from_def_id(item.owner_id.to_def_id()));
let attrs = self.tcx.hir().attrs(variant.id);
self.dumper.dump_def(
if !self.span.filter_generated(name_span) {
let span = self.span_from_span(name_span);
let id = id_from_hir_id(variant.id, &self.save_ctxt);
- let parent = Some(id_from_def_id(item.def_id.to_def_id()));
+ let parent = Some(id_from_def_id(item.owner_id.to_def_id()));
let attrs = self.tcx.hir().attrs(variant.id);
self.dumper.dump_def(
}
let map = self.tcx.hir();
- self.nest_typeck_results(item.def_id.def_id, |v| {
+ self.nest_typeck_results(item.owner_id.def_id, |v| {
v.visit_ty(&impl_.self_ty);
if let Some(trait_ref) = &impl_.of_trait {
v.process_path(trait_ref.hir_ref_id, &hir::QPath::Resolved(None, &trait_ref.path));
}
v.process_generic_params(&impl_.generics, "", item.hir_id());
for impl_item in impl_.items {
- v.process_impl_item(map.impl_item(impl_item.id), item.def_id.to_def_id());
+ v.process_impl_item(map.impl_item(impl_item.id), item.owner_id.to_def_id());
}
});
}
methods: &'tcx [hir::TraitItemRef],
) {
let name = item.ident.to_string();
- let qualname = format!("::{}", self.tcx.def_path_str(item.def_id.to_def_id()));
+ let qualname = format!("::{}", self.tcx.def_path_str(item.owner_id.to_def_id()));
let mut val = name.clone();
if !generics.params.is_empty() {
val.push_str(&generic_params_to_string(generics.params));
val.push_str(&bounds_to_string(trait_refs));
}
if !self.span.filter_generated(item.ident.span) {
- let id = id_from_def_id(item.def_id.to_def_id());
+ let id = id_from_def_id(item.owner_id.to_def_id());
let span = self.span_from_span(item.ident.span);
let children =
- methods.iter().map(|i| id_from_def_id(i.id.def_id.to_def_id())).collect();
+ methods.iter().map(|i| id_from_def_id(i.id.owner_id.to_def_id())).collect();
let attrs = self.tcx.hir().attrs(item.hir_id());
self.dumper.dump_def(
- &access_from!(self.save_ctxt, item.def_id.def_id),
+ &access_from!(self.save_ctxt, item.owner_id.def_id),
Def {
kind: DefKind::Trait,
id,
kind: RelationKind::SuperTrait,
span,
from: id_from_def_id(id),
- to: id_from_def_id(item.def_id.to_def_id()),
+ to: id_from_def_id(item.owner_id.to_def_id()),
});
}
}
self.process_generic_params(generics, &qualname, item.hir_id());
for method in methods {
let map = self.tcx.hir();
- self.process_trait_item(map.trait_item(method.id), item.def_id.to_def_id())
+ self.process_trait_item(map.trait_item(method.id), item.owner_id.to_def_id())
}
}
fn process_mod(&mut self, item: &'tcx hir::Item<'tcx>) {
if let Some(mod_data) = self.save_ctxt.get_item_data(item) {
down_cast_data!(mod_data, DefData, item.span);
- self.dumper.dump_def(&access_from!(self.save_ctxt, item.def_id.def_id), mod_data);
+ self.dumper.dump_def(&access_from!(self.save_ctxt, item.owner_id.def_id), mod_data);
}
}
let body = body.map(|b| self.tcx.hir().body(b).value);
let attrs = self.tcx.hir().attrs(trait_item.hir_id());
self.process_assoc_const(
- trait_item.def_id.def_id,
+ trait_item.owner_id.def_id,
trait_item.ident,
&ty,
body,
self.process_method(
sig,
body,
- trait_item.def_id.def_id,
+ trait_item.owner_id.def_id,
trait_item.ident,
&trait_item.generics,
trait_item.span,
// FIXME do something with _bounds (for type refs)
let name = trait_item.ident.name.to_string();
let qualname =
- format!("::{}", self.tcx.def_path_str(trait_item.def_id.to_def_id()));
+ format!("::{}", self.tcx.def_path_str(trait_item.owner_id.to_def_id()));
if !self.span.filter_generated(trait_item.ident.span) {
let span = self.span_from_span(trait_item.ident.span);
- let id = id_from_def_id(trait_item.def_id.to_def_id());
+ let id = id_from_def_id(trait_item.owner_id.to_def_id());
let attrs = self.tcx.hir().attrs(trait_item.hir_id());
self.dumper.dump_def(
let body = self.tcx.hir().body(body);
let attrs = self.tcx.hir().attrs(impl_item.hir_id());
self.process_assoc_const(
- impl_item.def_id.def_id,
+ impl_item.owner_id.def_id,
impl_item.ident,
&ty,
Some(&body.value),
self.process_method(
sig,
Some(body),
- impl_item.def_id.def_id,
+ impl_item.owner_id.def_id,
impl_item.ident,
&impl_item.generics,
impl_item.span,
let filename = sm.span_to_filename(krate_mod.spans.inner_span);
let data_id = id_from_hir_id(id, &self.save_ctxt);
let children =
- krate_mod.item_ids.iter().map(|i| id_from_def_id(i.def_id.to_def_id())).collect();
+ krate_mod.item_ids.iter().map(|i| id_from_def_id(i.owner_id.to_def_id())).collect();
let span = self.span_from_span(krate_mod.spans.inner_span);
let attrs = self.tcx.hir().attrs(id);
hir::ItemKind::Use(path, hir::UseKind::Single) => {
let sub_span = path.segments.last().unwrap().ident.span;
if !self.span.filter_generated(sub_span) {
- let access = access_from!(self.save_ctxt, item.def_id.def_id);
+ let access = access_from!(self.save_ctxt, item.owner_id.def_id);
let ref_id = self.lookup_def_id(item.hir_id()).map(id_from_def_id);
let span = self.span_from_span(sub_span);
- let parent = self.save_ctxt.tcx.local_parent(item.def_id.def_id);
+ let parent = self.save_ctxt.tcx.local_parent(item.owner_id.def_id);
self.dumper.import(
&access,
Import {
}
hir::ItemKind::Use(path, hir::UseKind::Glob) => {
// Make a comma-separated list of names of imported modules.
- let names = self.tcx.names_imported_by_glob_use(item.def_id.def_id);
+ let names = self.tcx.names_imported_by_glob_use(item.owner_id.def_id);
let names: Vec<_> = names.iter().map(|n| n.to_string()).collect();
// Otherwise it's a span with wrong macro expansion info, which
// we don't want to track anyway, since it's probably macro-internal `use`
if let Some(sub_span) = self.span.sub_span_of_star(item.span) {
if !self.span.filter_generated(item.span) {
- let access = access_from!(self.save_ctxt, item.def_id.def_id);
+ let access = access_from!(self.save_ctxt, item.owner_id.def_id);
let span = self.span_from_span(sub_span);
- let parent = self.save_ctxt.tcx.local_parent(item.def_id.def_id);
+ let parent = self.save_ctxt.tcx.local_parent(item.owner_id.def_id);
self.dumper.import(
&access,
Import {
let name_span = item.ident.span;
if !self.span.filter_generated(name_span) {
let span = self.span_from_span(name_span);
- let parent = self.save_ctxt.tcx.local_parent(item.def_id.def_id);
+ let parent = self.save_ctxt.tcx.local_parent(item.owner_id.def_id);
self.dumper.import(
&Access { public: false, reachable: false },
Import {
intravisit::walk_mod(self, m, item.hir_id());
}
hir::ItemKind::TyAlias(ty, ref generics) => {
- let qualname = format!("::{}", self.tcx.def_path_str(item.def_id.to_def_id()));
+ let qualname = format!("::{}", self.tcx.def_path_str(item.owner_id.to_def_id()));
let value = ty_to_string(&ty);
if !self.span.filter_generated(item.ident.span) {
let span = self.span_from_span(item.ident.span);
- let id = id_from_def_id(item.def_id.to_def_id());
+ let id = id_from_def_id(item.owner_id.to_def_id());
let attrs = self.tcx.hir().attrs(item.hir_id());
self.dumper.dump_def(
- &access_from!(self.save_ctxt, item.def_id.def_id),
+ &access_from!(self.save_ctxt, item.owner_id.def_id),
Def {
kind: DefKind::Type,
id,
}
hir::TyKind::OpaqueDef(item_id, _, _) => {
let item = self.tcx.hir().item(item_id);
- self.nest_typeck_results(item_id.def_id.def_id, |v| v.visit_item(item));
+ self.nest_typeck_results(item_id.owner_id.def_id, |v| v.visit_item(item));
}
_ => intravisit::walk_ty(self, t),
}
}
fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem<'tcx>) {
- let access = access_from!(self.save_ctxt, item.def_id.def_id);
+ let access = access_from!(self.save_ctxt, item.owner_id.def_id);
match item.kind {
hir::ForeignItemKind::Fn(decl, _, ref generics) => {
use rustc_hir::Node;
use rustc_hir_pretty::{enum_def_to_string, fn_to_string, ty_to_string};
use rustc_middle::hir::nested_filter;
-use rustc_middle::middle::privacy::AccessLevels;
+use rustc_middle::middle::privacy::EffectiveVisibilities;
use rustc_middle::ty::{self, print::with_no_trimmed_paths, DefIdTree, TyCtxt};
use rustc_middle::{bug, span_bug};
use rustc_session::config::{CrateType, Input, OutputType};
pub struct SaveContext<'tcx> {
tcx: TyCtxt<'tcx>,
maybe_typeck_results: Option<&'tcx ty::TypeckResults<'tcx>>,
- access_levels: &'tcx AccessLevels,
+ effective_visibilities: &'tcx EffectiveVisibilities,
span_utils: SpanUtils<'tcx>,
config: Config,
impl_counter: Cell<u32>,
}
pub fn get_extern_item_data(&self, item: &hir::ForeignItem<'_>) -> Option<Data> {
- let def_id = item.def_id.to_def_id();
+ let def_id = item.owner_id.to_def_id();
let qualname = format!("::{}", self.tcx.def_path_str(def_id));
let attrs = self.tcx.hir().attrs(item.hir_id());
match item.kind {
}
pub fn get_item_data(&self, item: &hir::Item<'_>) -> Option<Data> {
- let def_id = item.def_id.to_def_id();
+ let def_id = item.owner_id.to_def_id();
let attrs = self.tcx.hir().attrs(item.hir_id());
match item.kind {
hir::ItemKind::Fn(ref sig, ref generics, _) => {
children: m
.item_ids
.iter()
- .map(|i| id_from_def_id(i.def_id.to_def_id()))
+ .map(|i| id_from_def_id(i.owner_id.to_def_id()))
.collect(),
decl_id: None,
docs: self.docs_for_attrs(attrs),
parent: None,
children: items
.iter()
- .map(|i| id_from_def_id(i.id.def_id.to_def_id()))
+ .map(|i| id_from_def_id(i.id.owner_id.to_def_id()))
.collect(),
docs: String::new(),
sig: None,
info!("Dumping crate {}", cratename);
// Privacy checking must be done outside of type inference; use a
- // fallback in case the access levels couldn't have been correctly computed.
- let access_levels = match tcx.sess.compile_status() {
- Ok(..) => tcx.privacy_access_levels(()),
- Err(..) => tcx.arena.alloc(AccessLevels::default()),
+ // fallback in case effective visibilities couldn't have been correctly computed.
+ let effective_visibilities = match tcx.sess.compile_status() {
+ Ok(..) => tcx.effective_visibilities(()),
+ Err(..) => tcx.arena.alloc(EffectiveVisibilities::default()),
};
let save_ctxt = SaveContext {
tcx,
maybe_typeck_results: None,
- access_levels: &access_levels,
+ effective_visibilities: &effective_visibilities,
span_utils: SpanUtils::new(&tcx.sess),
config: find_config(config),
impl_counter: Cell::new(0),
}
let name = self.ident.to_string();
let defs = vec![SigElement {
- id: id_from_def_id(self.def_id.to_def_id()),
+ id: id_from_def_id(self.owner_id.to_def_id()),
start: offset + text.len(),
end: offset + text.len() + name.len(),
}];
let mut text = "const ".to_owned();
let name = self.ident.to_string();
let defs = vec![SigElement {
- id: id_from_def_id(self.def_id.to_def_id()),
+ id: id_from_def_id(self.owner_id.to_def_id()),
start: offset + text.len(),
end: offset + text.len() + name.len(),
}];
let mut text = "mod ".to_owned();
let name = self.ident.to_string();
let defs = vec![SigElement {
- id: id_from_def_id(self.def_id.to_def_id()),
+ id: id_from_def_id(self.owner_id.to_def_id()),
start: offset + text.len(),
end: offset + text.len() + name.len(),
}];
}
let name = self.ident.to_string();
let defs = vec![SigElement {
- id: id_from_def_id(self.def_id.to_def_id()),
+ id: id_from_def_id(self.owner_id.to_def_id()),
start: offset + text.len(),
end: offset + text.len() + name.len(),
}];
let mut text = "type ".to_owned();
let name = self.ident.to_string();
let defs = vec![SigElement {
- id: id_from_def_id(self.def_id.to_def_id()),
+ id: id_from_def_id(self.owner_id.to_def_id()),
start: offset + text.len(),
end: offset + text.len() + name.len(),
}];
[dependencies]
indexmap = "1.9.1"
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
-thin-vec = "0.2.8"
+thin-vec = "0.2.9"
[dev-dependencies]
rustc_macros = { path = "../rustc_macros" }
rustc_fs_util = { path = "../rustc_fs_util" }
rustc_ast = { path = "../rustc_ast" }
rustc_lint_defs = { path = "../rustc_lint_defs" }
+smallvec = "1.8.1"
+
+[target.'cfg(unix)'.dependencies]
+libc = "0.2"
+
+[target.'cfg(windows)'.dependencies]
+winapi = { version = "0.3", features = ["libloaderapi"] }
NativeStaticLibs,
StackProtectorStrategies,
LinkArgs,
+ SplitDebuginfo,
}
pub enum Input {
actually_rustdoc: false,
trimmed_def_paths: TrimmedDefPaths::default(),
cli_forced_codegen_units: None,
- cli_forced_thinlto_off: false,
+ cli_forced_local_thinlto_off: false,
remap_path_prefix: Vec::new(),
real_rust_source_base_dir: None,
edition: DEFAULT_EDITION,
report_delayed_bugs: self.report_delayed_bugs,
macro_backtrace: self.macro_backtrace,
deduplicate_diagnostics: self.deduplicate_diagnostics,
+ track_diagnostics: self.track_diagnostics,
}
}
}
error_format: ErrorOutputType,
mut codegen_units: Option<usize>,
) -> (bool, Option<usize>) {
- let mut disable_thinlto = false;
+ let mut disable_local_thinlto = false;
// Issue #30063: if user requests LLVM-related output to one
// particular path, disable codegen-units.
let incompatible: Vec<_> = output_types
}
early_warn(error_format, "resetting to default -C codegen-units=1");
codegen_units = Some(1);
- disable_thinlto = true;
+ disable_local_thinlto = true;
}
}
_ => {
codegen_units = Some(1);
- disable_thinlto = true;
+ disable_local_thinlto = true;
}
}
}
early_error(error_format, "value for codegen units must be a positive non-zero integer");
}
- (disable_thinlto, codegen_units)
+ (disable_local_thinlto, codegen_units)
}
fn check_thread_count(unstable_opts: &UnstableOptions, error_format: ErrorOutputType) {
cg.target_feature = String::new();
}
- prints.extend(matches.opt_strs("print").into_iter().map(|s| match &*s {
- "crate-name" => PrintRequest::CrateName,
- "file-names" => PrintRequest::FileNames,
- "sysroot" => PrintRequest::Sysroot,
- "target-libdir" => PrintRequest::TargetLibdir,
- "cfg" => PrintRequest::Cfg,
- "calling-conventions" => PrintRequest::CallingConventions,
- "target-list" => PrintRequest::TargetList,
- "target-cpus" => PrintRequest::TargetCPUs,
- "target-features" => PrintRequest::TargetFeatures,
- "relocation-models" => PrintRequest::RelocationModels,
- "code-models" => PrintRequest::CodeModels,
- "tls-models" => PrintRequest::TlsModels,
- "native-static-libs" => PrintRequest::NativeStaticLibs,
- "stack-protector-strategies" => PrintRequest::StackProtectorStrategies,
- "target-spec-json" => {
- if unstable_opts.unstable_options {
- PrintRequest::TargetSpec
- } else {
+ const PRINT_REQUESTS: &[(&str, PrintRequest)] = &[
+ ("crate-name", PrintRequest::CrateName),
+ ("file-names", PrintRequest::FileNames),
+ ("sysroot", PrintRequest::Sysroot),
+ ("target-libdir", PrintRequest::TargetLibdir),
+ ("cfg", PrintRequest::Cfg),
+ ("calling-conventions", PrintRequest::CallingConventions),
+ ("target-list", PrintRequest::TargetList),
+ ("target-cpus", PrintRequest::TargetCPUs),
+ ("target-features", PrintRequest::TargetFeatures),
+ ("relocation-models", PrintRequest::RelocationModels),
+ ("code-models", PrintRequest::CodeModels),
+ ("tls-models", PrintRequest::TlsModels),
+ ("native-static-libs", PrintRequest::NativeStaticLibs),
+ ("stack-protector-strategies", PrintRequest::StackProtectorStrategies),
+ ("target-spec-json", PrintRequest::TargetSpec),
+ ("link-args", PrintRequest::LinkArgs),
+ ("split-debuginfo", PrintRequest::SplitDebuginfo),
+ ];
+
+ prints.extend(matches.opt_strs("print").into_iter().map(|req| {
+ match PRINT_REQUESTS.iter().find(|&&(name, _)| name == req) {
+ Some((_, PrintRequest::TargetSpec)) => {
+ if unstable_opts.unstable_options {
+ PrintRequest::TargetSpec
+ } else {
+ early_error(
+ error_format,
+ "the `-Z unstable-options` flag must also be passed to \
+ enable the target-spec-json print option",
+ );
+ }
+ }
+ Some(&(_, print_request)) => print_request,
+ None => {
+ let prints =
+ PRINT_REQUESTS.iter().map(|(name, _)| format!("`{name}`")).collect::<Vec<_>>();
+ let prints = prints.join(", ");
early_error(
error_format,
- "the `-Z unstable-options` flag must also be passed to \
- enable the target-spec-json print option",
+ &format!("unknown print request `{req}`. Valid print requests are: {prints}"),
);
}
}
- "link-args" => PrintRequest::LinkArgs,
- req => early_error(error_format, &format!("unknown print request `{req}`")),
}));
prints
let output_types = parse_output_types(&unstable_opts, matches, error_format);
let mut cg = CodegenOptions::build(matches, error_format);
- let (disable_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
+ let (disable_local_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
&output_types,
matches,
error_format,
let sysroot = match &sysroot_opt {
Some(s) => s,
None => {
- tmp_buf = crate::filesearch::get_or_default_sysroot();
+ tmp_buf = crate::filesearch::get_or_default_sysroot().expect("Failed finding sysroot");
&tmp_buf
}
};
actually_rustdoc: false,
trimmed_def_paths: TrimmedDefPaths::default(),
cli_forced_codegen_units: codegen_units,
- cli_forced_thinlto_off: disable_thinlto,
+ cli_forced_local_thinlto_off: disable_local_thinlto,
remap_path_prefix,
real_rust_source_base_dir,
edition,
//! A module for searching for libraries
+use smallvec::{smallvec, SmallVec};
use std::env;
use std::fs;
use std::iter::FromIterator;
PathBuf::from_iter([sysroot, Path::new(&rustlib_path), Path::new("lib")])
}
+#[cfg(unix)]
+fn current_dll_path() -> Result<PathBuf, String> {
+ use std::ffi::{CStr, OsStr};
+ use std::os::unix::prelude::*;
+
+ unsafe {
+ let addr = current_dll_path as usize as *mut _;
+ let mut info = std::mem::zeroed();
+ if libc::dladdr(addr, &mut info) == 0 {
+ return Err("dladdr failed".into());
+ }
+ if info.dli_fname.is_null() {
+ return Err("dladdr returned null pointer".into());
+ }
+ let bytes = CStr::from_ptr(info.dli_fname).to_bytes();
+ let os = OsStr::from_bytes(bytes);
+ Ok(PathBuf::from(os))
+ }
+}
+
+#[cfg(windows)]
+fn current_dll_path() -> Result<PathBuf, String> {
+ use std::ffi::OsString;
+ use std::io;
+ use std::os::windows::prelude::*;
+ use std::ptr;
+
+ use winapi::um::libloaderapi::{
+ GetModuleFileNameW, GetModuleHandleExW, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+ };
+
+ unsafe {
+ let mut module = ptr::null_mut();
+ let r = GetModuleHandleExW(
+ GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+ current_dll_path as usize as *mut _,
+ &mut module,
+ );
+ if r == 0 {
+ return Err(format!("GetModuleHandleExW failed: {}", io::Error::last_os_error()));
+ }
+ let mut space = Vec::with_capacity(1024);
+ let r = GetModuleFileNameW(module, space.as_mut_ptr(), space.capacity() as u32);
+ if r == 0 {
+ return Err(format!("GetModuleFileNameW failed: {}", io::Error::last_os_error()));
+ }
+ let r = r as usize;
+ if r >= space.capacity() {
+ return Err(format!("our buffer was too small? {}", io::Error::last_os_error()));
+ }
+ space.set_len(r);
+ let os = OsString::from_wide(&space);
+ Ok(PathBuf::from(os))
+ }
+}
+
+pub fn sysroot_candidates() -> SmallVec<[PathBuf; 2]> {
+ let target = crate::config::host_triple();
+ let mut sysroot_candidates: SmallVec<[PathBuf; 2]> =
+ smallvec![get_or_default_sysroot().expect("Failed finding sysroot")];
+ let path = current_dll_path().and_then(|s| Ok(s.canonicalize().map_err(|e| e.to_string())?));
+ if let Ok(dll) = path {
+ // use `parent` twice to chop off the file name and then also the
+ // directory containing the dll which should be either `lib` or `bin`.
+ if let Some(path) = dll.parent().and_then(|p| p.parent()) {
+ // The original `path` pointed at the `rustc_driver` crate's dll.
+ // Now that dll should only be in one of two locations. The first is
+ // in the compiler's libdir, for example `$sysroot/lib/*.dll`. The
+ // other is the target's libdir, for example
+ // `$sysroot/lib/rustlib/$target/lib/*.dll`.
+ //
+ // We don't know which, so let's assume that if our `path` above
+ // ends in `$target` we *could* be in the target libdir, and always
+ // assume that we may be in the main libdir.
+ sysroot_candidates.push(path.to_owned());
+
+ if path.ends_with(target) {
+ sysroot_candidates.extend(
+ path.parent() // chop off `$target`
+ .and_then(|p| p.parent()) // chop off `rustlib`
+ .and_then(|p| p.parent()) // chop off `lib`
+ .map(|s| s.to_owned()),
+ );
+ }
+ }
+ }
+
+ return sysroot_candidates;
+}
+
/// This function checks if sysroot is found using env::args().next(), and if it
-/// is not found, uses env::current_exe() to imply sysroot.
-pub fn get_or_default_sysroot() -> PathBuf {
+/// is not found, finds sysroot from current rustc_driver dll.
+pub fn get_or_default_sysroot() -> Result<PathBuf, String> {
// Follow symlinks. If the resolved path is relative, make it absolute.
fn canonicalize(path: PathBuf) -> PathBuf {
let path = fs::canonicalize(&path).unwrap_or(path);
fix_windows_verbatim_for_gcc(&path)
}
- // Use env::current_exe() to get the path of the executable following
- // symlinks/canonicalizing components.
- fn from_current_exe() -> PathBuf {
- match env::current_exe() {
- Ok(exe) => {
- let mut p = canonicalize(exe);
- p.pop();
- p.pop();
- p
- }
- Err(e) => panic!("failed to get current_exe: {e}"),
+ fn default_from_rustc_driver_dll() -> Result<PathBuf, String> {
+ let dll = current_dll_path().and_then(|s| Ok(canonicalize(s)))?;
+
+ // `dll` will be in one of the following two:
+ // - compiler's libdir: $sysroot/lib/*.dll
+ // - target's libdir: $sysroot/lib/rustlib/$target/lib/*.dll
+ //
+ // use `parent` twice to chop off the file name and then also the
+ // directory containing the dll
+ let dir = dll.parent().and_then(|p| p.parent()).ok_or(format!(
+ "Could not move 2 levels upper using `parent()` on {}",
+ dll.display()
+ ))?;
+
+ // if `dir` points target's dir, move up to the sysroot
+ if dir.ends_with(crate::config::host_triple()) {
+ dir.parent() // chop off `$target`
+ .and_then(|p| p.parent()) // chop off `rustlib`
+ .and_then(|p| p.parent()) // chop off `lib`
+ .map(|s| s.to_owned())
+ .ok_or(format!(
+ "Could not move 3 levels upper using `parent()` on {}",
+ dir.display()
+ ))
+ } else {
+ Ok(dir.to_owned())
}
}
}
}
- // Check if sysroot is found using env::args().next(), and if is not found,
- // use env::current_exe() to imply sysroot.
- from_env_args_next().unwrap_or_else(from_current_exe)
+ Ok(from_env_args_next().unwrap_or(default_from_rustc_driver_dll()?))
}
#[rustc_lint_opt_deny_field_access("use `Session::codegen_units` instead of this field")]
cli_forced_codegen_units: Option<usize> [UNTRACKED],
#[rustc_lint_opt_deny_field_access("use `Session::lto` instead of this field")]
- cli_forced_thinlto_off: bool [UNTRACKED],
+ cli_forced_local_thinlto_off: bool [UNTRACKED],
/// Remap source path prefixes in all output (messages, object files, debug, etc.).
remap_path_prefix: Vec<(PathBuf, PathBuf)> [TRACKED_NO_CRATE_HASH],
"choose the TLS model to use (`rustc --print tls-models` for details)"),
trace_macros: bool = (false, parse_bool, [UNTRACKED],
"for every macro invocation, print its name and arguments (default: no)"),
+ track_diagnostics: bool = (false, parse_bool, [UNTRACKED],
+ "tracks where in rustc a diagnostic was emitted"),
// Diagnostics are considered side-effects of a query (see `QuerySideEffects`) and are saved
// alongside query results and changes to translation options can affect diagnostics - so
// translation options should be tracked.
///
/// This variant allows you to control whether it is a library or language feature.
/// Almost always, you want to use this for a language feature. If so, prefer `feature_err`.
+#[track_caller]
pub fn feature_err_issue<'a>(
sess: &'a ParseSess,
feature: Symbol,
self.proc_macro_quoted_spans.lock().clone()
}
+ #[track_caller]
pub fn create_err<'a>(
&'a self,
err: impl IntoDiagnostic<'a>,
err.into_diagnostic(&self.span_diagnostic)
}
+ #[track_caller]
pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed {
self.create_err(err).emit()
}
+ #[track_caller]
pub fn create_warning<'a>(
&'a self,
warning: impl IntoDiagnostic<'a, ()>,
warning.into_diagnostic(&self.span_diagnostic)
}
+ #[track_caller]
pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) {
self.create_warning(warning).emit()
}
}
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_err(
&self,
msg: impl Into<DiagnosticMessage>,
}
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_span_warn<S: Into<MultiSpan>>(
&self,
sp: S,
self.diagnostic().struct_span_warn(sp, msg)
}
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_span_warn_with_expectation<S: Into<MultiSpan>>(
&self,
sp: S,
self.diagnostic().struct_span_warn_with_expectation(sp, msg, id)
}
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_span_warn_with_code<S: Into<MultiSpan>>(
&self,
sp: S,
self.diagnostic().struct_span_warn_with_code(sp, msg, code)
}
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
self.diagnostic().struct_warn(msg)
}
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_warn_with_expectation(
&self,
msg: impl Into<DiagnosticMessage>,
self.diagnostic().struct_warn_with_expectation(msg, id)
}
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_span_allow<S: Into<MultiSpan>>(
&self,
sp: S,
self.diagnostic().struct_span_allow(sp, msg)
}
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
self.diagnostic().struct_allow(msg)
}
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_expect(
&self,
msg: impl Into<DiagnosticMessage>,
self.diagnostic().struct_expect(msg, id)
}
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_span_err<S: Into<MultiSpan>>(
&self,
sp: S,
self.diagnostic().struct_span_err(sp, msg)
}
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_span_err_with_code<S: Into<MultiSpan>>(
&self,
sp: S,
}
// FIXME: This method should be removed (every error should have an associated error code).
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_err(
&self,
msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
self.parse_sess.struct_err(msg)
}
+ #[track_caller]
#[rustc_lint_diagnostics]
pub fn struct_err_with_code(
&self,
self.diagnostic().struct_err_with_code(msg, code)
}
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_warn_with_code(
&self,
msg: impl Into<DiagnosticMessage>,
self.diagnostic().struct_warn_with_code(msg, code)
}
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_span_fatal<S: Into<MultiSpan>>(
&self,
sp: S,
}
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) -> ! {
self.diagnostic().span_fatal(sp, msg)
}
self.diagnostic().fatal(msg).raise()
}
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn span_err_or_warn<S: Into<MultiSpan>>(
&self,
is_warning: bool,
}
}
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn span_err<S: Into<MultiSpan>>(
&self,
sp: S,
pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
self.diagnostic().err(msg)
}
+ #[track_caller]
pub fn create_err<'a>(
&'a self,
err: impl IntoDiagnostic<'a>,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
self.parse_sess.create_err(err)
}
+ #[track_caller]
pub fn create_feature_err<'a>(
&'a self,
err: impl IntoDiagnostic<'a>,
add_feature_diagnostics(&mut err, &self.parse_sess, feature);
err
}
+ #[track_caller]
pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed {
self.parse_sess.emit_err(err)
}
+ #[track_caller]
pub fn create_warning<'a>(
&'a self,
err: impl IntoDiagnostic<'a, ()>,
) -> DiagnosticBuilder<'a, ()> {
self.parse_sess.create_warning(err)
}
+ #[track_caller]
pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) {
self.parse_sess.emit_warning(warning)
}
+ #[track_caller]
pub fn create_note<'a>(
&'a self,
note: impl IntoDiagnostic<'a, Noted>,
) -> DiagnosticBuilder<'a, Noted> {
self.parse_sess.create_note(note)
}
+ #[track_caller]
pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted {
self.parse_sess.emit_note(note)
}
+ #[track_caller]
pub fn create_fatal<'a>(
&'a self,
fatal: impl IntoDiagnostic<'a, !>,
) -> DiagnosticBuilder<'a, !> {
self.parse_sess.create_fatal(fatal)
}
+ #[track_caller]
pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, !>) -> ! {
self.parse_sess.emit_fatal(fatal)
}
}
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
+ #[track_caller]
pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) {
self.diagnostic().span_warn(sp, msg)
}
pub fn note_without_error(&self, msg: impl Into<DiagnosticMessage>) {
self.diagnostic().note_without_error(msg)
}
+
+ #[track_caller]
pub fn span_note_without_error<S: Into<MultiSpan>>(
&self,
sp: S,
return config::Lto::Fat;
}
config::LtoCli::Thin => {
- return if self.opts.cli_forced_thinlto_off {
- config::Lto::Fat
- } else {
- config::Lto::Thin
- };
+ // The user explicitly asked for ThinLTO
+ return config::Lto::Thin;
}
}
// If processing command line options determined that we're incompatible
// with ThinLTO (e.g., `-C lto --emit llvm-ir`) then return that option.
- if self.opts.cli_forced_thinlto_off {
+ if self.opts.cli_forced_local_thinlto_off {
return config::Lto::No;
}
fallback_bundle: LazyFallbackBundle,
) -> Box<dyn Emitter + sync::Send> {
let macro_backtrace = sopts.unstable_opts.macro_backtrace;
+ let track_diagnostics = sopts.unstable_opts.track_diagnostics;
match sopts.error_format {
config::ErrorOutputType::HumanReadable(kind) => {
let (short, color_config) = kind.unzip();
sopts.unstable_opts.teach,
sopts.diagnostic_width,
macro_backtrace,
+ track_diagnostics,
);
Box::new(emitter.ui_testing(sopts.unstable_opts.ui_testing))
}
json_rendered,
sopts.diagnostic_width,
macro_backtrace,
+ track_diagnostics,
)
.ui_testing(sopts.unstable_opts.ui_testing),
),
let sysroot = match &sopts.maybe_sysroot {
Some(sysroot) => sysroot.clone(),
- None => filesearch::get_or_default_sysroot(),
+ None => filesearch::get_or_default_sysroot().expect("Failed finding sysroot"),
};
let target_cfg = config::build_target_config(&sopts, target_override, &sysroot);
false,
None,
false,
+ false,
))
}
- config::ErrorOutputType::Json { pretty, json_rendered } => {
- Box::new(JsonEmitter::basic(pretty, json_rendered, None, fallback_bundle, None, false))
- }
+ config::ErrorOutputType::Json { pretty, json_rendered } => Box::new(JsonEmitter::basic(
+ pretty,
+ json_rendered,
+ None,
+ fallback_bundle,
+ None,
+ false,
+ false,
+ )),
};
rustc_errors::Handler::with_emitter(true, None, emitter)
}
self.data_untracked().is_dummy()
}
- /// Returns `true` if this span comes from a macro or desugaring.
+ /// Returns `true` if this span comes from any kind of macro, desugaring or inlining.
#[inline]
pub fn from_expansion(self) -> bool {
self.ctxt() != SyntaxContext::root()
matches!(outer_expn.kind, ExpnKind::Macro(..)) && outer_expn.collapse_debuginfo
}
+ /// Returns `true` if this span comes from MIR inlining.
+ pub fn is_inlined(self) -> bool {
+ let outer_expn = self.ctxt().outer_expn_data();
+ matches!(outer_expn.kind, ExpnKind::Inlined)
+ }
+
/// Returns `true` if `span` originates in a derive-macro's expansion.
pub fn in_derive_expansion(self) -> bool {
matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
/// Returns a new span representing the next character after the end-point of this span.
/// Special cases:
/// - if span is a dummy one, returns the same span
- /// - if next_point reached the end of source, return span with lo = hi
+ /// - if next_point reached the end of source, return a span exceeding the end of source,
+ /// which means sm.span_to_snippet(next_point) will get `Err`
/// - respect multi-byte characters
pub fn next_point(&self, sp: Span) -> Span {
if sp.is_dummy() {
let start_of_next_point = sp.hi().0;
let width = self.find_width_of_character_at_span(sp, true);
- if width == 0 {
- return Span::new(sp.hi(), sp.hi(), sp.ctxt(), None);
- }
// If the width is 1, then the next span should only contain the next char besides current ending.
// However, in the case of a multibyte character, where the width != 1, the next span should
// span multiple bytes to include the whole character.
// Ensure indexes are also not malformed.
if start_index > end_index || end_index > source_len - 1 {
debug!("find_width_of_character_at_span: source indexes are malformed");
- return 0;
+ return 1;
}
let src = local_begin.sf.external_src.borrow();
assert_eq!(span.lo().0, 4);
assert_eq!(span.hi().0, 5);
- // A non-empty span at the last byte should advance to create an empty
- // span pointing at the end of the file.
+ // Reaching to the end of file, return a span that will get error with `span_to_snippet`
let span = Span::with_root_ctxt(BytePos(4), BytePos(5));
let span = sm.next_point(span);
assert_eq!(span.lo().0, 5);
- assert_eq!(span.hi().0, 5);
+ assert_eq!(span.hi().0, 6);
+ assert!(sm.span_to_snippet(span).is_err());
- // Empty span pointing just past the last byte.
+ // Reaching to the end of file, return a span that will get error with `span_to_snippet`
let span = Span::with_root_ctxt(BytePos(5), BytePos(5));
let span = sm.next_point(span);
assert_eq!(span.lo().0, 5);
- assert_eq!(span.hi().0, 5);
+ assert_eq!(span.hi().0, 6);
+ assert!(sm.span_to_snippet(span).is_err());
}
export_name,
expr,
extended_key_value_attributes,
+ extended_varargs_abi_support,
extern_absolute_paths,
extern_crate_item_prelude,
extern_crate_self,
impl_lint_pass,
impl_macros,
impl_trait_in_bindings,
+ impl_trait_in_fn_trait_return,
implied_by,
import,
import_name_type,
}
}
+// takes advantage of `str::to_string` specialization
+impl ToString for Symbol {
+ fn to_string(&self) -> String {
+ self.as_str().to_string()
+ }
+}
+
impl<S: Encoder> Encodable<S> for Symbol {
default fn encode(&self, s: &mut S) {
s.emit_str(self.as_str());
let crate_items = tcx.hir_crate_items(());
for id in crate_items.items() {
- symbol_names.process_attrs(id.def_id.def_id);
+ symbol_names.process_attrs(id.owner_id.def_id);
}
for id in crate_items.trait_items() {
- symbol_names.process_attrs(id.def_id.def_id);
+ symbol_names.process_attrs(id.owner_id.def_id);
}
for id in crate_items.impl_items() {
- symbol_names.process_attrs(id.def_id.def_id);
+ symbol_names.process_attrs(id.owner_id.def_id);
}
for id in crate_items.foreign_items() {
- symbol_names.process_attrs(id.def_id.def_id);
+ symbol_names.process_attrs(id.owner_id.def_id);
}
})
}
let lifetimes = regions
.into_iter()
.map(|br| match br {
- ty::BrAnon(i) => i,
+ ty::BrAnon(i, _) => i,
_ => bug!("symbol_names: non-anonymized region `{:?}` in `{:?}`", br, value),
})
.max()
// Late-bound lifetimes use indices starting at 1,
// see `BinderLevel` for more details.
- ty::ReLateBound(debruijn, ty::BoundRegion { kind: ty::BrAnon(i), .. }) => {
+ ty::ReLateBound(debruijn, ty::BoundRegion { kind: ty::BrAnon(i, _), .. }) => {
let binder = &self.binders[self.binders.len() - 1 - debruijn.index()];
let depth = binder.lifetime_depths.start + i;
.builtin_deref(true)
.expect("tried to dereference on non-ptr type")
.ty;
- let dereferenced_const =
- self.tcx.mk_const(ty::ConstS { kind: ct.kind(), ty: pointee_ty });
+ let dereferenced_const = self.tcx.mk_const(ct.kind(), pointee_ty);
self = dereferenced_const.print(self)?;
}
}
RustCold,
}
+impl Abi {
+ pub fn supports_varargs(self) -> bool {
+ // * C and Cdecl obviously support varargs.
+ // * C can be based on SysV64 or Win64, so they must support varargs.
+ // * EfiApi is based on Win64 or C, so it also supports it.
+ //
+ // * Stdcall does not, because it would be impossible for the callee to clean
+ // up the arguments. (callee doesn't know how many arguments are there)
+ // * Same for Fastcall, Vectorcall and Thiscall.
+ // * System can become Stdcall, so is also a no-no.
+ // * Other calling conventions are related to hardware or the compiler itself.
+ match self {
+ Self::C { .. }
+ | Self::Cdecl { .. }
+ | Self::Win64 { .. }
+ | Self::SysV64 { .. }
+ | Self::EfiApi => true,
+ _ => false,
+ }
+ }
+}
+
#[derive(Copy, Clone)]
pub struct AbiData {
abi: Abi,
--- /dev/null
+use crate::spec::{
+ aarch64_apple_ios_sim, aarch64_apple_watchos_sim, x86_64_apple_ios, x86_64_apple_tvos,
+ x86_64_apple_watchos_sim,
+};
+
+#[test]
+fn simulator_targets_set_abi() {
+ let all_sim_targets = [
+ x86_64_apple_ios::target(),
+ x86_64_apple_tvos::target(),
+ x86_64_apple_watchos_sim::target(),
+ aarch64_apple_ios_sim::target(),
+ // Note: There is currently no ARM64 tvOS simulator target
+ aarch64_apple_watchos_sim::target(),
+ ];
+
+ for target in all_sim_targets {
+ assert_eq!(target.abi, "sim")
+ }
+}
use crate::spec::{cvs, TargetOptions};
use std::borrow::Cow;
+#[cfg(test)]
+#[path = "apple/tests.rs"]
+mod tests;
+
use Arch::*;
#[allow(non_camel_case_types)]
#[derive(Copy, Clone)]
Arm64,
Arm64_32,
I386,
+ #[allow(dead_code)] // Some targets don't use this enum...
X86_64,
+ X86_64_sim,
X86_64_macabi,
Arm64_macabi,
Arm64_sim,
Arm64 | Arm64_macabi | Arm64_sim => "arm64",
Arm64_32 => "arm64_32",
I386 => "i386",
- X86_64 | X86_64_macabi => "x86_64",
+ X86_64 | X86_64_sim | X86_64_macabi => "x86_64",
}
}
match arch {
Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | X86_64 => "",
X86_64_macabi | Arm64_macabi => "macabi",
- Arm64_sim => "sim",
+ // x86_64-apple-ios is a simulator target, even though it isn't
+ // declared that way in the target like the other ones...
+ Arm64_sim | X86_64_sim => "sim",
}
}
Arm64 => "apple-a7",
Arm64_32 => "apple-s4",
I386 => "yonah",
- X86_64 => "core2",
+ X86_64 | X86_64_sim => "core2",
X86_64_macabi => "core2",
Arm64_macabi => "apple-a12",
Arm64_sim => "apple-a12",
fn link_env_remove(arch: Arch) -> Cow<'static, [Cow<'static, str>]> {
match arch {
- Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | X86_64 | Arm64_sim => {
+ Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | X86_64 | X86_64_sim | Arm64_sim => {
cvs!["MACOSX_DEPLOYMENT_TARGET"]
}
X86_64_macabi | Arm64_macabi => cvs!["IPHONEOS_DEPLOYMENT_TARGET"],
}
pub fn opts(os: &'static str, arch: Arch) -> TargetOptions {
+ let abi = target_abi(arch);
TargetOptions {
- abi: target_abi(arch).into(),
+ abi: abi.into(),
cpu: target_cpu(arch).into(),
link_env_remove: link_env_remove(arch),
has_thread_local: false,
- ..super::apple_base::opts(os, target_arch_name(arch), target_abi(arch))
+ ..super::apple_base::opts(os, target_arch_name(arch), abi)
}
}
--- /dev/null
+use crate::spec::{cvs, Cc, LinkerFlavor, Lld, PanicStrategy, RelocModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+ Target {
+ llvm_target: "mipsel-sony-psx".into(),
+ pointer_width: 32,
+ data_layout: "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64".into(),
+ arch: "mips".into(),
+
+ options: TargetOptions {
+ os: "none".into(),
+ env: "psx".into(),
+ vendor: "sony".into(),
+ linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes),
+ cpu: "mips1".into(),
+ executables: true,
+ linker: Some("rust-lld".into()),
+ relocation_model: RelocModel::Static,
+ exe_suffix: ".exe".into(),
+
+ // PSX doesn't natively support floats.
+ features: "+soft-float".into(),
+
+ // This should be 16 bits, but LLVM incorrectly tries emitting MIPS-II SYNC instructions
+ // for atomic loads and stores. This crashes rustc so we have to disable the Atomic* API
+ // until this is fixed upstream. See https://reviews.llvm.org/D122427#3420144 for more
+ // info.
+ max_atomic_width: Some(0),
+
+ // PSX does not support trap-on-condition instructions.
+ llvm_args: cvs!["-mno-check-zero-division"],
+ llvm_abiname: "o32".into(),
+ panic_strategy: PanicStrategy::Abort,
+ ..Default::default()
+ },
+ }
+}
("armv7a-kmc-solid_asp3-eabihf", armv7a_kmc_solid_asp3_eabihf),
("mipsel-sony-psp", mipsel_sony_psp),
+ ("mipsel-sony-psx", mipsel_sony_psx),
("mipsel-unknown-none", mipsel_unknown_none),
("thumbv4t-none-eabi", thumbv4t_none_eabi),
("armv4t-none-eabi", armv4t_none_eabi),
Target {
llvm_target: "riscv64-unknown-freebsd".into(),
pointer_width: 64,
- data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".into(),
+ data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
arch: "riscv64".into(),
options: TargetOptions {
code_model: Some(CodeModel::Medium),
Target {
llvm_target: "riscv64-unknown-linux-gnu".into(),
pointer_width: 64,
- data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".into(),
+ data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
arch: "riscv64".into(),
options: TargetOptions {
code_model: Some(CodeModel::Medium),
Target {
llvm_target: "riscv64-unknown-linux-musl".into(),
pointer_width: 64,
- data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".into(),
+ data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
arch: "riscv64".into(),
options: TargetOptions {
code_model: Some(CodeModel::Medium),
pub fn target() -> Target {
Target {
- data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".into(),
+ data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
llvm_target: "riscv64".into(),
pointer_width: 64,
arch: "riscv64".into(),
Target {
llvm_target: "riscv64-unknown-openbsd".into(),
pointer_width: 64,
- data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".into(),
+ data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
arch: "riscv64".into(),
options: TargetOptions {
code_model: Some(CodeModel::Medium),
pub fn target() -> Target {
Target {
- data_layout: "e-m:e-p:64:64-i64:64-i128:128-n64-S128".into(),
+ data_layout: "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128".into(),
llvm_target: "riscv64".into(),
pointer_width: 64,
arch: "riscv64".into(),
-use crate::spec::{cvs, Cc, LinkerFlavor, Lld, TargetOptions};
+use crate::spec::{cvs, Cc, DebuginfoKind, LinkerFlavor, Lld, SplitDebuginfo, TargetOptions};
+use std::borrow::Cow;
pub fn opts() -> TargetOptions {
// We cannot use `-nodefaultlibs` because compiler-rt has to be passed
eh_frame_header: false,
no_default_libraries: false,
has_thread_local: true,
-
+ // FIXME(davidtwco): Support Split DWARF on Windows GNU - may require LLVM changes to
+ // output DWO, despite using DWARF, doesn't use ELF..
+ debuginfo_kind: DebuginfoKind::Pdb,
+ supported_split_debuginfo: Cow::Borrowed(&[SplitDebuginfo::Off]),
..Default::default()
}
}
use crate::spec::{StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
- let base = opts("ios", Arch::X86_64);
+ let base = opts("ios", Arch::X86_64_sim);
let llvm_target = super::apple_base::ios_sim_llvm_target("x86_64");
Target {
use crate::spec::{StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
- let base = opts("tvos", Arch::X86_64);
+ let base = opts("tvos", Arch::X86_64_sim);
Target {
llvm_target: "x86_64-apple-tvos".into(),
pointer_width: 64,
use crate::spec::{StackProbeType, Target, TargetOptions};
pub fn target() -> Target {
- let base = opts("watchos", Arch::X86_64);
+ let base = opts("watchos", Arch::X86_64_sim);
let arch = "x86_64";
let llvm_target = super::apple_base::watchos_sim_llvm_target(arch);
}
impl IntoDiagnostic<'_> for NegativePositiveConflict<'_> {
+ #[track_caller]
fn into_diagnostic(
self,
handler: &Handler,
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
-use crate::traits::{self, TraitEngine, TraitEngineExt};
+use crate::traits::{self, ObligationCtxt};
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
let ty = self.resolve_vars_if_possible(ty);
if !(param_env, ty).needs_infer() {
- return ty.is_copy_modulo_regions(self.tcx.at(span), param_env);
+ return ty.is_copy_modulo_regions(self.tcx, param_env);
}
let copy_def_id = self.tcx.require_lang_item(LangItem::Copy, None);
/// Normalizes associated types in `value`, potentially returning
/// new obligations that must further be processed.
+ #[instrument(level = "debug", skip(self, cause, param_env), ret)]
fn partially_normalize_associated_types_in<T>(
&self,
cause: ObligationCause<'tcx>,
where
T: TypeFoldable<'tcx>,
{
- debug!("partially_normalize_associated_types_in(value={:?})", value);
let mut selcx = traits::SelectionContext::new(self);
let traits::Normalized { value, obligations } =
traits::normalize(&mut selcx, param_env, cause, value);
- debug!(
- "partially_normalize_associated_types_in: result={:?} predicates={:?}",
- value, obligations
- );
InferOk { value, obligations }
}
+ #[instrument(level = "debug", skip(self), ret)]
fn type_implements_trait(
&self,
trait_def_id: DefId,
params: SubstsRef<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> traits::EvaluationResult {
- debug!(
- "type_implements_trait: trait_def_id={:?}, type={:?}, params={:?}, param_env={:?}",
- trait_def_id, ty, params, param_env
- );
-
let trait_ref =
ty::TraitRef { def_id: trait_def_id, substs: self.tcx.mk_substs_trait(ty, params) };
fn enter_canonical_trait_query<K, R>(
&mut self,
canonical_key: &Canonical<'tcx, K>,
- operation: impl FnOnce(&InferCtxt<'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible<R>,
+ operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Fallible<R>,
) -> Fallible<CanonicalizedQueryResponse<'tcx, R>>
where
K: TypeFoldable<'tcx>,
fn enter_canonical_trait_query<K, R>(
&mut self,
canonical_key: &Canonical<'tcx, K>,
- operation: impl FnOnce(&InferCtxt<'tcx>, &mut dyn TraitEngine<'tcx>, K) -> Fallible<R>,
+ operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Fallible<R>,
) -> Fallible<CanonicalizedQueryResponse<'tcx, R>>
where
K: TypeFoldable<'tcx>,
R: Debug + TypeFoldable<'tcx>,
Canonical<'tcx, QueryResponse<'tcx, R>>: ArenaAllocatable<'tcx>,
{
- let (ref infcx, key, canonical_inference_vars) =
+ let (infcx, key, canonical_inference_vars) =
self.build_with_canonical(DUMMY_SP, canonical_key);
- let mut fulfill_cx = <dyn TraitEngine<'_>>::new(infcx.tcx);
- let value = operation(infcx, &mut *fulfill_cx, key)?;
- infcx.make_canonicalized_query_response(canonical_inference_vars, value, &mut *fulfill_cx)
+ let ocx = ObligationCtxt::new(&infcx);
+ let value = operation(&ocx, key)?;
+ ocx.make_canonicalized_query_response(canonical_inference_vars, value)
}
}
obligations: FxIndexSet<PredicateObligation<'tcx>>,
relationships: FxHashMap<ty::TyVid, ty::FoundRelationships>,
+
+ usable_in_snapshot: bool,
}
impl FulfillmentContext<'_> {
FulfillmentContext {
obligations: FxIndexSet::default(),
relationships: FxHashMap::default(),
+ usable_in_snapshot: false,
}
}
+
+ pub(crate) fn new_in_snapshot() -> Self {
+ FulfillmentContext { usable_in_snapshot: true, ..Self::new() }
+ }
}
impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
infcx: &InferCtxt<'tcx>,
obligation: PredicateObligation<'tcx>,
) {
- assert!(!infcx.is_in_snapshot());
+ if !self.usable_in_snapshot {
+ assert!(!infcx.is_in_snapshot());
+ }
let obligation = infcx.resolve_vars_if_possible(obligation);
super::relationships::update(self, infcx, &obligation);
}
fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
- assert!(!infcx.is_in_snapshot());
+ if !self.usable_in_snapshot {
+ assert!(!infcx.is_in_snapshot());
+ }
let mut errors = Vec::new();
let mut next_round = FxIndexSet::default();
}
let concrete = infcx.const_eval_resolve(param_env, uv, Some(span));
match concrete {
- Err(ErrorHandled::TooGeneric) => {
- Err(NotConstEvaluatable::Error(infcx.tcx.sess.delay_span_bug(
- span,
- format!("Missing value for constant, but no error reported?"),
- )))
- }
+ Err(ErrorHandled::TooGeneric) => Err(NotConstEvaluatable::Error(
+ infcx
+ .tcx
+ .sess
+ .delay_span_bug(span, "Missing value for constant, but no error reported?"),
+ )),
Err(ErrorHandled::Linted) => {
let reported = infcx
.tcx
use std::cell::RefCell;
+use std::fmt::Debug;
use super::TraitEngine;
use super::{ChalkFulfillmentContext, FulfillmentContext};
use crate::infer::InferCtxtExt;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_infer::infer::at::ToTrace;
+use rustc_infer::infer::canonical::{
+ Canonical, CanonicalVarValues, CanonicalizedQueryResponse, QueryResponse,
+};
use rustc_infer::infer::{InferCtxt, InferOk};
+use rustc_infer::traits::query::Fallible;
use rustc_infer::traits::{
FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _,
};
+use rustc_middle::arena::ArenaAllocatable;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::ToPredicate;
use rustc_middle::ty::TypeFoldable;
fn new_in_snapshot(tcx: TyCtxt<'tcx>) -> Box<Self> {
if tcx.sess.opts.unstable_opts.chalk {
- Box::new(ChalkFulfillmentContext::new())
+ Box::new(ChalkFulfillmentContext::new_in_snapshot())
} else {
Box::new(FulfillmentContext::new_in_snapshot())
}
self.register_infer_ok_obligations(infer_ok)
}
- pub fn equate_types(
+ pub fn eq<T: ToTrace<'tcx>>(
&self,
cause: &ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- expected: Ty<'tcx>,
- actual: Ty<'tcx>,
+ expected: T,
+ actual: T,
) -> Result<(), TypeError<'tcx>> {
- match self.infcx.at(cause, param_env).eq(expected, actual) {
+ self.infcx
+ .at(cause, param_env)
+ .eq(expected, actual)
+ .map(|infer_ok| self.register_infer_ok_obligations(infer_ok))
+ }
+
+ pub fn sup<T: ToTrace<'tcx>>(
+ &self,
+ cause: &ObligationCause<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ expected: T,
+ actual: T,
+ ) -> Result<(), TypeError<'tcx>> {
+ match self.infcx.at(cause, param_env).sup(expected, actual) {
Ok(InferOk { obligations, value: () }) => {
self.register_obligations(obligations);
Ok(())
}
}
+ pub fn select_where_possible(&self) -> Vec<FulfillmentError<'tcx>> {
+ self.engine.borrow_mut().select_where_possible(self.infcx)
+ }
+
pub fn select_all_or_error(&self) -> Vec<FulfillmentError<'tcx>> {
self.engine.borrow_mut().select_all_or_error(self.infcx)
}
}
implied_bounds
}
+
+ pub fn make_canonicalized_query_response<T>(
+ &self,
+ inference_vars: CanonicalVarValues<'tcx>,
+ answer: T,
+ ) -> Fallible<CanonicalizedQueryResponse<'tcx, T>>
+ where
+ T: Debug + TypeFoldable<'tcx>,
+ Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>,
+ {
+ self.infcx.make_canonicalized_query_response(
+ inference_vars,
+ answer,
+ &mut **self.engine.borrow_mut(),
+ )
+ }
}
--- /dev/null
+use rustc_hir::def_id::DefId;
+use rustc_infer::infer::InferCtxt;
+use rustc_infer::traits::{Obligation, ObligationCause, TraitObligation};
+use rustc_span::DUMMY_SP;
+
+use crate::traits::ObligationCtxt;
+
+pub fn recompute_applicable_impls<'tcx>(
+ infcx: &InferCtxt<'tcx>,
+ obligation: &TraitObligation<'tcx>,
+) -> Vec<DefId> {
+ let tcx = infcx.tcx;
+ let param_env = obligation.param_env;
+ let dummy_cause = ObligationCause::dummy();
+ let impl_may_apply = |impl_def_id| {
+ let ocx = ObligationCtxt::new_in_snapshot(infcx);
+ let placeholder_obligation =
+ infcx.replace_bound_vars_with_placeholders(obligation.predicate);
+ let obligation_trait_ref =
+ ocx.normalize(dummy_cause.clone(), param_env, placeholder_obligation.trait_ref);
+
+ let impl_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id);
+ let impl_trait_ref = tcx.bound_impl_trait_ref(impl_def_id).unwrap().subst(tcx, impl_substs);
+ let impl_trait_ref = ocx.normalize(ObligationCause::dummy(), param_env, impl_trait_ref);
+
+ if let Err(_) = ocx.eq(&dummy_cause, param_env, obligation_trait_ref, impl_trait_ref) {
+ return false;
+ }
+
+ let impl_predicates = tcx.predicates_of(impl_def_id).instantiate(tcx, impl_substs);
+ ocx.register_obligations(
+ impl_predicates
+ .predicates
+ .iter()
+ .map(|&predicate| Obligation::new(dummy_cause.clone(), param_env, predicate)),
+ );
+
+ ocx.select_where_possible().is_empty()
+ };
+
+ let mut impls = Vec::new();
+ tcx.for_each_relevant_impl(
+ obligation.predicate.def_id(),
+ obligation.predicate.skip_binder().trait_ref.self_ty(),
+ |impl_def_id| {
+ if infcx.probe(move |_snapshot| impl_may_apply(impl_def_id)) {
+ impls.push(impl_def_id)
+ }
+ },
+ );
+ impls
+}
+mod ambiguity;
pub mod on_unimplemented;
pub mod suggestions;
use super::{
FulfillmentContext, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes,
- Obligation, ObligationCause, ObligationCauseCode, OnUnimplementedDirective,
- OnUnimplementedNote, OutputTypeParameterMismatch, Overflow, PredicateObligation,
- SelectionContext, SelectionError, TraitNotObjectSafe,
+ Obligation, ObligationCause, ObligationCauseCode, OutputTypeParameterMismatch, Overflow,
+ PredicateObligation, SelectionContext, SelectionError, TraitNotObjectSafe,
};
-
use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::infer::{self, InferCtxt, TyCtxtInferExt};
+use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
+use crate::traits::query::normalize::AtExt as _;
+use crate::traits::specialize::to_pretty_impl_header;
+use on_unimplemented::OnUnimplementedNote;
+use on_unimplemented::TypeErrCtxtExt as _;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
use std::fmt;
use std::iter;
use std::ops::ControlFlow;
-
-use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
-use crate::traits::query::normalize::AtExt as _;
-use crate::traits::specialize::to_pretty_impl_header;
-use on_unimplemented::TypeErrCtxtExt as _;
use suggestions::TypeErrCtxtExt as _;
pub use rustc_infer::traits::error_reporting::*;
&self,
errors: &[FulfillmentError<'tcx>],
body_id: Option<hir::BodyId>,
- fallback_has_occurred: bool,
) -> ErrorGuaranteed;
fn report_overflow_error<T>(
obligation: PredicateObligation<'tcx>,
root_obligation: &PredicateObligation<'tcx>,
error: &SelectionError<'tcx>,
- fallback_has_occurred: bool,
);
}
&self,
errors: &[FulfillmentError<'tcx>],
body_id: Option<hir::BodyId>,
- fallback_has_occurred: bool,
) -> ErrorGuaranteed {
#[derive(Debug)]
struct ErrorDescriptor<'tcx> {
for (error, suppressed) in iter::zip(errors, is_suppressed) {
if !suppressed {
- self.report_fulfillment_error(error, body_id, fallback_has_occurred);
+ self.report_fulfillment_error(error, body_id);
}
}
mut obligation: PredicateObligation<'tcx>,
root_obligation: &PredicateObligation<'tcx>,
error: &SelectionError<'tcx>,
- fallback_has_occurred: bool,
) {
self.set_tainted_by_errors();
let tcx = self.tcx;
let mut span = obligation.cause.span;
let mut err = match *error {
- SelectionError::Ambiguous(ref impls) => {
- let mut err = self.tcx.sess.struct_span_err(
- obligation.cause.span,
- &format!("multiple applicable `impl`s for `{}`", obligation.predicate),
- );
- self.annotate_source_of_ambiguity(&mut err, impls, obligation.predicate);
- err.emit();
- return;
- }
SelectionError::Unimplemented => {
// If this obligation was generated as a result of well-formedness checking, see if we
// can get a better error message by performing HIR-based well-formedness checking.
}
}
+ if Some(trait_ref.def_id()) == tcx.lang_items().tuple_trait() {
+ match obligation.cause.code().peel_derives() {
+ ObligationCauseCode::RustCall => {
+ err.set_primary_message("functions with the \"rust-call\" ABI must take a single non-self tuple argument");
+ }
+ ObligationCauseCode::BindingObligation(def_id, _)
+ | ObligationCauseCode::ItemObligation(def_id)
+ if ty::ClosureKind::from_def_id(tcx, *def_id).is_some() =>
+ {
+ err.code(rustc_errors::error_code!(E0059));
+ err.set_primary_message(format!(
+ "type parameter to bare `{}` trait must be a tuple",
+ tcx.def_path_str(*def_id)
+ ));
+ }
+ _ => {}
+ }
+ }
+
if Some(trait_ref.def_id()) == tcx.lang_items().drop_trait()
&& predicate_is_const
{
);
}
- let is_fn_trait = [
- self.tcx.lang_items().fn_trait(),
- self.tcx.lang_items().fn_mut_trait(),
- self.tcx.lang_items().fn_once_trait(),
- ]
- .contains(&Some(trait_ref.def_id()));
+ let is_fn_trait =
+ ty::ClosureKind::from_def_id(tcx, trait_ref.def_id()).is_some();
let is_target_feature_fn = if let ty::FnDef(def_id, _) =
*trait_ref.skip_binder().self_ty().kind()
{
// useful for less general traits.
if peeled
&& !self.tcx.trait_is_auto(def_id)
- && !self.tcx.lang_items().items().contains(&Some(def_id))
+ && !self.tcx.lang_items().iter().any(|(_, id)| id == def_id)
{
let trait_ref = trait_pred.to_poly_trait_ref();
let impl_candidates =
// variable that used to fallback to `()` now falling back to `!`. Issue a
// note informing about the change in behaviour.
if trait_predicate.skip_binder().self_ty().is_never()
- && fallback_has_occurred
+ && self.fallback_has_occurred
{
let predicate = trait_predicate.map_bound(|mut trait_pred| {
trait_pred.trait_ref.substs = self.tcx.mk_substs_trait(
&self,
error: &FulfillmentError<'tcx>,
body_id: Option<hir::BodyId>,
- fallback_has_occurred: bool,
);
fn report_projection_error(
&self,
error: &FulfillmentError<'tcx>,
body_id: Option<hir::BodyId>,
- fallback_has_occurred: bool,
) {
match error.code {
FulfillmentErrorCode::CodeSelectionError(ref selection_error) => {
error.obligation.clone(),
&error.root_obligation,
selection_error,
- fallback_has_occurred,
);
}
FulfillmentErrorCode::CodeProjectionError(ref e) => {
let def_id = trait_ref.def_id();
if impl_candidates.is_empty() {
if self.tcx.trait_is_auto(def_id)
- || self.tcx.lang_items().items().contains(&Some(def_id))
+ || self.tcx.lang_items().iter().any(|(_, id)| id == def_id)
|| self.tcx.get_diagnostic_name(def_id).is_some()
{
// Mentioning implementers of `Copy`, `Debug` and friends is not useful.
crate::traits::TraitQueryMode::Standard,
);
match selcx.select_from_obligation(&obligation) {
- Err(SelectionError::Ambiguous(impls)) if impls.len() > 1 => {
- self.annotate_source_of_ambiguity(&mut err, &impls, predicate);
+ Ok(None) => {
+ let impls = ambiguity::recompute_applicable_impls(self.infcx, &obligation);
+ let has_non_region_infer =
+ trait_ref.skip_binder().substs.types().any(|t| !t.is_ty_infer());
+ // It doesn't make sense to talk about applicable impls if there are more
+ // than a handful of them.
+ if impls.len() > 1 && impls.len() < 5 && has_non_region_infer {
+ self.annotate_source_of_ambiguity(&mut err, &impls, predicate);
+ } else {
+ if self.is_tainted_by_errors() {
+ err.delay_as_bug();
+ return;
+ }
+ err.note(&format!("cannot satisfy `{}`", predicate));
+ }
}
_ => {
if self.is_tainted_by_errors() {
- err.cancel();
+ err.delay_as_bug();
return;
}
err.note(&format!("cannot satisfy `{}`", predicate));
}
}
}
- let msg = format!("multiple `impl`s satisfying `{}` found", predicate);
let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{}`", n)).collect();
crate_names.sort();
crate_names.dedup();
err.downgrade_to_delayed_bug();
return;
}
- let post = if post.len() > 4 {
- format!(
- ":\n{}\nand {} more",
- post.iter().map(|p| format!("- {}", p)).take(4).collect::<Vec<_>>().join("\n"),
- post.len() - 4,
- )
- } else if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) {
+
+ let msg = format!("multiple `impl`s satisfying `{}` found", predicate);
+ let post = if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) {
format!(":\n{}", post.iter().map(|p| format!("- {}", p)).collect::<Vec<_>>().join("\n"),)
} else if post.len() == 1 {
format!(": `{}`", post[0])
-use super::{
- ObligationCauseCode, OnUnimplementedDirective, OnUnimplementedNote, PredicateObligation,
-};
+use super::{ObligationCauseCode, PredicateObligation};
use crate::infer::error_reporting::TypeErrCtxt;
+use rustc_ast::{MetaItem, NestedMetaItem};
+use rustc_attr as attr;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::{struct_span_err, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_middle::ty::SubstsRef;
-use rustc_middle::ty::{self, GenericParamDefKind};
-use rustc_span::symbol::sym;
+use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
+use rustc_parse_format::{ParseMode, Parser, Piece, Position};
+use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::{Span, DUMMY_SP};
use std::iter;
+use crate::errors::{
+ EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented,
+};
+
use super::InferCtxtPrivExt;
pub trait TypeErrCtxtExt<'tcx> {
}
}
}
+
+#[derive(Clone, Debug)]
+pub struct OnUnimplementedFormatString(Symbol);
+
+#[derive(Debug)]
+pub struct OnUnimplementedDirective {
+ pub condition: Option<MetaItem>,
+ pub subcommands: Vec<OnUnimplementedDirective>,
+ pub message: Option<OnUnimplementedFormatString>,
+ pub label: Option<OnUnimplementedFormatString>,
+ pub note: Option<OnUnimplementedFormatString>,
+ pub parent_label: Option<OnUnimplementedFormatString>,
+ pub append_const_msg: Option<Option<Symbol>>,
+}
+
+/// For the `#[rustc_on_unimplemented]` attribute
+#[derive(Default)]
+pub struct OnUnimplementedNote {
+ pub message: Option<String>,
+ pub label: Option<String>,
+ pub note: Option<String>,
+ pub parent_label: Option<String>,
+ /// Append a message for `~const Trait` errors. `None` means not requested and
+ /// should fallback to a generic message, `Some(None)` suggests using the default
+ /// appended message, `Some(Some(s))` suggests use the `s` message instead of the
+ /// default one..
+ pub append_const_msg: Option<Option<Symbol>>,
+}
+
+impl<'tcx> OnUnimplementedDirective {
+ fn parse(
+ tcx: TyCtxt<'tcx>,
+ item_def_id: DefId,
+ items: &[NestedMetaItem],
+ span: Span,
+ is_root: bool,
+ ) -> Result<Self, ErrorGuaranteed> {
+ let mut errored = None;
+ let mut item_iter = items.iter();
+
+ let parse_value = |value_str| {
+ OnUnimplementedFormatString::try_parse(tcx, item_def_id, value_str, span).map(Some)
+ };
+
+ let condition = if is_root {
+ None
+ } else {
+ let cond = item_iter
+ .next()
+ .ok_or_else(|| tcx.sess.emit_err(EmptyOnClauseInOnUnimplemented { span }))?
+ .meta_item()
+ .ok_or_else(|| tcx.sess.emit_err(InvalidOnClauseInOnUnimplemented { span }))?;
+ attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |cfg| {
+ if let Some(value) = cfg.value && let Err(guar) = parse_value(value) {
+ errored = Some(guar);
+ }
+ true
+ });
+ Some(cond.clone())
+ };
+
+ let mut message = None;
+ let mut label = None;
+ let mut note = None;
+ let mut parent_label = None;
+ let mut subcommands = vec![];
+ let mut append_const_msg = None;
+
+ for item in item_iter {
+ if item.has_name(sym::message) && message.is_none() {
+ if let Some(message_) = item.value_str() {
+ message = parse_value(message_)?;
+ continue;
+ }
+ } else if item.has_name(sym::label) && label.is_none() {
+ if let Some(label_) = item.value_str() {
+ label = parse_value(label_)?;
+ continue;
+ }
+ } else if item.has_name(sym::note) && note.is_none() {
+ if let Some(note_) = item.value_str() {
+ note = parse_value(note_)?;
+ continue;
+ }
+ } else if item.has_name(sym::parent_label) && parent_label.is_none() {
+ if let Some(parent_label_) = item.value_str() {
+ parent_label = parse_value(parent_label_)?;
+ continue;
+ }
+ } else if item.has_name(sym::on)
+ && is_root
+ && message.is_none()
+ && label.is_none()
+ && note.is_none()
+ {
+ if let Some(items) = item.meta_item_list() {
+ match Self::parse(tcx, item_def_id, &items, item.span(), false) {
+ Ok(subcommand) => subcommands.push(subcommand),
+ Err(reported) => errored = Some(reported),
+ };
+ continue;
+ }
+ } else if item.has_name(sym::append_const_msg) && append_const_msg.is_none() {
+ if let Some(msg) = item.value_str() {
+ append_const_msg = Some(Some(msg));
+ continue;
+ } else if item.is_word() {
+ append_const_msg = Some(None);
+ continue;
+ }
+ }
+
+ // nothing found
+ tcx.sess.emit_err(NoValueInOnUnimplemented { span: item.span() });
+ }
+
+ if let Some(reported) = errored {
+ Err(reported)
+ } else {
+ Ok(OnUnimplementedDirective {
+ condition,
+ subcommands,
+ message,
+ label,
+ note,
+ parent_label,
+ append_const_msg,
+ })
+ }
+ }
+
+ pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, ErrorGuaranteed> {
+ let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) else {
+ return Ok(None);
+ };
+
+ let result = if let Some(items) = attr.meta_item_list() {
+ Self::parse(tcx, item_def_id, &items, attr.span, true).map(Some)
+ } else if let Some(value) = attr.value_str() {
+ Ok(Some(OnUnimplementedDirective {
+ condition: None,
+ message: None,
+ subcommands: vec![],
+ label: Some(OnUnimplementedFormatString::try_parse(
+ tcx,
+ item_def_id,
+ value,
+ attr.span,
+ )?),
+ note: None,
+ parent_label: None,
+ append_const_msg: None,
+ }))
+ } else {
+ let reported =
+ tcx.sess.delay_span_bug(DUMMY_SP, "of_item: neither meta_item_list nor value_str");
+ return Err(reported);
+ };
+ debug!("of_item({:?}) = {:?}", item_def_id, result);
+ result
+ }
+
+ pub fn evaluate(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ trait_ref: ty::TraitRef<'tcx>,
+ options: &[(Symbol, Option<String>)],
+ ) -> OnUnimplementedNote {
+ let mut message = None;
+ let mut label = None;
+ let mut note = None;
+ let mut parent_label = None;
+ let mut append_const_msg = None;
+ info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
+
+ let options_map: FxHashMap<Symbol, String> =
+ options.iter().filter_map(|(k, v)| v.as_ref().map(|v| (*k, v.to_owned()))).collect();
+
+ for command in self.subcommands.iter().chain(Some(self)).rev() {
+ if let Some(ref condition) = command.condition && !attr::eval_condition(
+ condition,
+ &tcx.sess.parse_sess,
+ Some(tcx.features()),
+ &mut |cfg| {
+ let value = cfg.value.map(|v| {
+ OnUnimplementedFormatString(v).format(tcx, trait_ref, &options_map)
+ });
+
+ options.contains(&(cfg.name, value))
+ },
+ ) {
+ debug!("evaluate: skipping {:?} due to condition", command);
+ continue;
+ }
+ debug!("evaluate: {:?} succeeded", command);
+ if let Some(ref message_) = command.message {
+ message = Some(message_.clone());
+ }
+
+ if let Some(ref label_) = command.label {
+ label = Some(label_.clone());
+ }
+
+ if let Some(ref note_) = command.note {
+ note = Some(note_.clone());
+ }
+
+ if let Some(ref parent_label_) = command.parent_label {
+ parent_label = Some(parent_label_.clone());
+ }
+
+ append_const_msg = command.append_const_msg;
+ }
+
+ OnUnimplementedNote {
+ label: label.map(|l| l.format(tcx, trait_ref, &options_map)),
+ message: message.map(|m| m.format(tcx, trait_ref, &options_map)),
+ note: note.map(|n| n.format(tcx, trait_ref, &options_map)),
+ parent_label: parent_label.map(|e_s| e_s.format(tcx, trait_ref, &options_map)),
+ append_const_msg,
+ }
+ }
+}
+
+impl<'tcx> OnUnimplementedFormatString {
+ fn try_parse(
+ tcx: TyCtxt<'tcx>,
+ item_def_id: DefId,
+ from: Symbol,
+ err_sp: Span,
+ ) -> Result<Self, ErrorGuaranteed> {
+ let result = OnUnimplementedFormatString(from);
+ result.verify(tcx, item_def_id, err_sp)?;
+ Ok(result)
+ }
+
+ fn verify(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ item_def_id: DefId,
+ span: Span,
+ ) -> Result<(), ErrorGuaranteed> {
+ let trait_def_id = if tcx.is_trait(item_def_id) {
+ item_def_id
+ } else {
+ tcx.trait_id_of_impl(item_def_id)
+ .expect("expected `on_unimplemented` to correspond to a trait")
+ };
+ let trait_name = tcx.item_name(trait_def_id);
+ let generics = tcx.generics_of(item_def_id);
+ let s = self.0.as_str();
+ let parser = Parser::new(s, None, None, false, ParseMode::Format);
+ let mut result = Ok(());
+ for token in parser {
+ match token {
+ Piece::String(_) => (), // Normal string, no need to check it
+ Piece::NextArgument(a) => match a.position {
+ Position::ArgumentNamed(s) => {
+ match Symbol::intern(s) {
+ // `{Self}` is allowed
+ kw::SelfUpper => (),
+ // `{ThisTraitsName}` is allowed
+ s if s == trait_name => (),
+ // `{from_method}` is allowed
+ sym::from_method => (),
+ // `{from_desugaring}` is allowed
+ sym::from_desugaring => (),
+ // `{ItemContext}` is allowed
+ sym::ItemContext => (),
+ // `{integral}` and `{integer}` and `{float}` are allowed
+ sym::integral | sym::integer_ | sym::float => (),
+ // So is `{A}` if A is a type parameter
+ s => match generics.params.iter().find(|param| param.name == s) {
+ Some(_) => (),
+ None => {
+ let reported = struct_span_err!(
+ tcx.sess,
+ span,
+ E0230,
+ "there is no parameter `{}` on {}",
+ s,
+ if trait_def_id == item_def_id {
+ format!("trait `{}`", trait_name)
+ } else {
+ "impl".to_string()
+ }
+ )
+ .emit();
+ result = Err(reported);
+ }
+ },
+ }
+ }
+ // `{:1}` and `{}` are not to be used
+ Position::ArgumentIs(..) | Position::ArgumentImplicitlyIs(_) => {
+ let reported = struct_span_err!(
+ tcx.sess,
+ span,
+ E0231,
+ "only named substitution parameters are allowed"
+ )
+ .emit();
+ result = Err(reported);
+ }
+ },
+ }
+ }
+
+ result
+ }
+
+ pub fn format(
+ &self,
+ tcx: TyCtxt<'tcx>,
+ trait_ref: ty::TraitRef<'tcx>,
+ options: &FxHashMap<Symbol, String>,
+ ) -> String {
+ let name = tcx.item_name(trait_ref.def_id);
+ let trait_str = tcx.def_path_str(trait_ref.def_id);
+ let generics = tcx.generics_of(trait_ref.def_id);
+ let generic_map = generics
+ .params
+ .iter()
+ .filter_map(|param| {
+ let value = match param.kind {
+ GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
+ trait_ref.substs[param.index as usize].to_string()
+ }
+ GenericParamDefKind::Lifetime => return None,
+ };
+ let name = param.name;
+ Some((name, value))
+ })
+ .collect::<FxHashMap<Symbol, String>>();
+ let empty_string = String::new();
+
+ let s = self.0.as_str();
+ let parser = Parser::new(s, None, None, false, ParseMode::Format);
+ let item_context = (options.get(&sym::ItemContext)).unwrap_or(&empty_string);
+ parser
+ .map(|p| match p {
+ Piece::String(s) => s,
+ Piece::NextArgument(a) => match a.position {
+ Position::ArgumentNamed(s) => {
+ let s = Symbol::intern(s);
+ match generic_map.get(&s) {
+ Some(val) => val,
+ None if s == name => &trait_str,
+ None => {
+ if let Some(val) = options.get(&s) {
+ val
+ } else if s == sym::from_desugaring || s == sym::from_method {
+ // don't break messages using these two arguments incorrectly
+ &empty_string
+ } else if s == sym::ItemContext {
+ &item_context
+ } else if s == sym::integral {
+ "{integral}"
+ } else if s == sym::integer_ {
+ "{integer}"
+ } else if s == sym::float {
+ "{float}"
+ } else {
+ bug!(
+ "broken on_unimplemented {:?} for {:?}: \
+ no argument matching {:?}",
+ self.0,
+ trait_ref,
+ s
+ )
+ }
+ }
+ }
+ }
+ _ => bug!("broken on_unimplemented {:?} - bad format arg", self.0),
+ },
+ })
+ .collect()
+ }
+}
let mut never_suggest_borrow: Vec<_> =
[LangItem::Copy, LangItem::Clone, LangItem::Unpin, LangItem::Sized]
.iter()
- .filter_map(|lang_item| self.tcx.lang_items().require(*lang_item).ok())
+ .filter_map(|lang_item| self.tcx.lang_items().get(*lang_item))
.collect();
if let Some(def_id) = self.tcx.get_diagnostic_item(sym::Send) {
| ObligationCauseCode::CheckAssociatedTypeBounds { .. }
| ObligationCauseCode::LetElse
| ObligationCauseCode::BinOp { .. }
- | ObligationCauseCode::AscribeUserTypeProvePredicate(..) => {}
+ | ObligationCauseCode::AscribeUserTypeProvePredicate(..)
+ | ObligationCauseCode::RustCall => {}
ObligationCauseCode::SliceOrArrayElem => {
err.note("slice and array elements must have `Sized` type");
}
}
}
Err(errors) => {
- infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ infcx.err_ctxt().report_fulfillment_errors(&errors, None);
}
};
}
mod fulfill;
pub mod misc;
mod object_safety;
-mod on_unimplemented;
pub mod outlives_bounds;
mod project;
pub mod query;
pub use self::object_safety::is_vtable_safe_method;
pub use self::object_safety::MethodViolationCode;
pub use self::object_safety::ObjectSafetyViolation;
-pub use self::on_unimplemented::{OnUnimplementedDirective, OnUnimplementedNote};
pub use self::project::{normalize, normalize_projection_type, normalize_to};
pub use self::select::{EvaluationCache, SelectionCache, SelectionContext};
pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
}
/// Creates predicate obligations from the generic bounds.
+#[instrument(level = "debug", skip(cause, param_env))]
pub fn predicates_for_generics<'tcx>(
cause: impl Fn(usize, Span) -> ObligationCause<'tcx>,
param_env: ty::ParamEnv<'tcx>,
generic_bounds: ty::InstantiatedPredicates<'tcx>,
) -> impl Iterator<Item = PredicateObligation<'tcx>> {
- let generic_bounds = generic_bounds;
- debug!("predicates_for_generics(generic_bounds={:?})", generic_bounds);
-
std::iter::zip(generic_bounds.predicates, generic_bounds.spans).enumerate().map(
move |(idx, (predicate, span))| Obligation {
cause: cause(idx, span),
/// `bound` or is not known to meet bound (note that this is
/// conservative towards *no impl*, which is the opposite of the
/// `evaluate` methods).
+#[instrument(level = "debug", skip(infcx, param_env, span), ret)]
pub fn type_known_to_meet_bound_modulo_regions<'tcx>(
infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
def_id: DefId,
span: Span,
) -> bool {
- debug!(
- "type_known_to_meet_bound_modulo_regions(ty={:?}, bound={:?})",
- ty,
- infcx.tcx.def_path_str(def_id)
- );
-
let trait_ref =
ty::Binder::dummy(ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) });
let obligation = Obligation {
};
let result = infcx.predicate_must_hold_modulo_regions(&obligation);
- debug!(
- "type_known_to_meet_ty={:?} bound={} => {:?}",
- ty,
- infcx.tcx.def_path_str(def_id),
- result
- );
+ debug!(?result);
if result && ty.has_non_region_infer() {
// Because of inference "guessing", selection can sometimes claim
// *definitively* show that it implements `Copy`. Otherwise,
// assume it is move; linear is always ok.
match &errors[..] {
- [] => {
- debug!(
- "type_known_to_meet_bound_modulo_regions: ty={:?} bound={} success",
- ty,
- infcx.tcx.def_path_str(def_id)
- );
- true
- }
+ [] => true,
errors => {
- debug!(
- ?ty,
- bound = %infcx.tcx.def_path_str(def_id),
- ?errors,
- "type_known_to_meet_bound_modulo_regions"
- );
+ debug!(?errors);
false
}
}
let predicates = match fully_normalize(&infcx, cause, elaborated_env, predicates) {
Ok(predicates) => predicates,
Err(errors) => {
- let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None, false);
+ let reported = infcx.err_ctxt().report_fulfillment_errors(&errors, None);
return Err(reported);
}
};
}
/// Normalize a type and process all resulting obligations, returning any errors
+#[instrument(skip_all)]
pub fn fully_normalize<'tcx, T>(
infcx: &InferCtxt<'tcx>,
cause: ObligationCause<'tcx>,
where
T: TypeFoldable<'tcx>,
{
- debug!("fully_normalize_with_fulfillcx(value={:?})", value);
- let selcx = &mut SelectionContext::new(infcx);
- let Normalized { value: normalized_value, obligations } =
- project::normalize(selcx, param_env, cause, value);
- debug!(
- "fully_normalize: normalized_value={:?} obligations={:?}",
- normalized_value, obligations
- );
-
- let mut fulfill_cx = FulfillmentContext::new();
- for obligation in obligations {
- fulfill_cx.register_predicate_obligation(infcx, obligation);
- }
-
- debug!("fully_normalize: select_all_or_error start");
- let errors = fulfill_cx.select_all_or_error(infcx);
+ let ocx = ObligationCtxt::new(infcx);
+ debug!(?value);
+ let normalized_value = ocx.normalize(cause, param_env, value);
+ debug!(?normalized_value);
+ debug!("select_all_or_error start");
+ let errors = ocx.select_all_or_error();
if !errors.is_empty() {
return Err(errors);
}
- debug!("fully_normalize: select_all_or_error complete");
+ debug!("select_all_or_error complete");
let resolved_value = infcx.resolve_vars_if_possible(normalized_value);
- debug!("fully_normalize: resolved_value={:?}", resolved_value);
+ debug!(?resolved_value);
Ok(resolved_value)
}
def_id: unsize_trait_did,
substs: tcx.mk_substs_trait(source, &[target.into()]),
};
- let obligation = Obligation::new(
- ObligationCause::dummy(),
- ty::ParamEnv::reveal_all(),
- ty::Binder::dummy(ty::TraitPredicate {
- trait_ref,
- constness: ty::BoundConstness::NotConst,
- polarity: ty::ImplPolarity::Positive,
- }),
- );
-
- let infcx = tcx.infer_ctxt().build();
- let mut selcx = SelectionContext::new(&infcx);
- let implsrc = selcx.select(&obligation).unwrap();
-
- let Some(ImplSource::TraitUpcasting(implsrc_traitcasting)) = implsrc else {
- bug!();
- };
- implsrc_traitcasting.vtable_vptr_slot
+ match tcx.codegen_select_candidate((ty::ParamEnv::reveal_all(), ty::Binder::dummy(trait_ref))) {
+ Ok(ImplSource::TraitUpcasting(implsrc_traitcasting)) => {
+ implsrc_traitcasting.vtable_vptr_slot
+ }
+ otherwise => bug!("expected TraitUpcasting candidate, got {otherwise:?}"),
+ }
}
pub fn provide(providers: &mut ty::query::Providers) {
+++ /dev/null
-use rustc_ast::{MetaItem, NestedMetaItem};
-use rustc_attr as attr;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{struct_span_err, ErrorGuaranteed};
-use rustc_hir::def_id::DefId;
-use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
-use rustc_parse_format::{ParseMode, Parser, Piece, Position};
-use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_span::{Span, DUMMY_SP};
-
-use crate::errors::{
- EmptyOnClauseInOnUnimplemented, InvalidOnClauseInOnUnimplemented, NoValueInOnUnimplemented,
-};
-
-#[derive(Clone, Debug)]
-pub struct OnUnimplementedFormatString(Symbol);
-
-#[derive(Debug)]
-pub struct OnUnimplementedDirective {
- pub condition: Option<MetaItem>,
- pub subcommands: Vec<OnUnimplementedDirective>,
- pub message: Option<OnUnimplementedFormatString>,
- pub label: Option<OnUnimplementedFormatString>,
- pub note: Option<OnUnimplementedFormatString>,
- pub parent_label: Option<OnUnimplementedFormatString>,
- pub append_const_msg: Option<Option<Symbol>>,
-}
-
-#[derive(Default)]
-pub struct OnUnimplementedNote {
- pub message: Option<String>,
- pub label: Option<String>,
- pub note: Option<String>,
- pub parent_label: Option<String>,
- /// Append a message for `~const Trait` errors. `None` means not requested and
- /// should fallback to a generic message, `Some(None)` suggests using the default
- /// appended message, `Some(Some(s))` suggests use the `s` message instead of the
- /// default one..
- pub append_const_msg: Option<Option<Symbol>>,
-}
-
-impl<'tcx> OnUnimplementedDirective {
- fn parse(
- tcx: TyCtxt<'tcx>,
- item_def_id: DefId,
- items: &[NestedMetaItem],
- span: Span,
- is_root: bool,
- ) -> Result<Self, ErrorGuaranteed> {
- let mut errored = None;
- let mut item_iter = items.iter();
-
- let parse_value = |value_str| {
- OnUnimplementedFormatString::try_parse(tcx, item_def_id, value_str, span).map(Some)
- };
-
- let condition = if is_root {
- None
- } else {
- let cond = item_iter
- .next()
- .ok_or_else(|| tcx.sess.emit_err(EmptyOnClauseInOnUnimplemented { span }))?
- .meta_item()
- .ok_or_else(|| tcx.sess.emit_err(InvalidOnClauseInOnUnimplemented { span }))?;
- attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |cfg| {
- if let Some(value) = cfg.value && let Err(guar) = parse_value(value) {
- errored = Some(guar);
- }
- true
- });
- Some(cond.clone())
- };
-
- let mut message = None;
- let mut label = None;
- let mut note = None;
- let mut parent_label = None;
- let mut subcommands = vec![];
- let mut append_const_msg = None;
-
- for item in item_iter {
- if item.has_name(sym::message) && message.is_none() {
- if let Some(message_) = item.value_str() {
- message = parse_value(message_)?;
- continue;
- }
- } else if item.has_name(sym::label) && label.is_none() {
- if let Some(label_) = item.value_str() {
- label = parse_value(label_)?;
- continue;
- }
- } else if item.has_name(sym::note) && note.is_none() {
- if let Some(note_) = item.value_str() {
- note = parse_value(note_)?;
- continue;
- }
- } else if item.has_name(sym::parent_label) && parent_label.is_none() {
- if let Some(parent_label_) = item.value_str() {
- parent_label = parse_value(parent_label_)?;
- continue;
- }
- } else if item.has_name(sym::on)
- && is_root
- && message.is_none()
- && label.is_none()
- && note.is_none()
- {
- if let Some(items) = item.meta_item_list() {
- match Self::parse(tcx, item_def_id, &items, item.span(), false) {
- Ok(subcommand) => subcommands.push(subcommand),
- Err(reported) => errored = Some(reported),
- };
- continue;
- }
- } else if item.has_name(sym::append_const_msg) && append_const_msg.is_none() {
- if let Some(msg) = item.value_str() {
- append_const_msg = Some(Some(msg));
- continue;
- } else if item.is_word() {
- append_const_msg = Some(None);
- continue;
- }
- }
-
- // nothing found
- tcx.sess.emit_err(NoValueInOnUnimplemented { span: item.span() });
- }
-
- if let Some(reported) = errored {
- Err(reported)
- } else {
- Ok(OnUnimplementedDirective {
- condition,
- subcommands,
- message,
- label,
- note,
- parent_label,
- append_const_msg,
- })
- }
- }
-
- pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result<Option<Self>, ErrorGuaranteed> {
- let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) else {
- return Ok(None);
- };
-
- let result = if let Some(items) = attr.meta_item_list() {
- Self::parse(tcx, item_def_id, &items, attr.span, true).map(Some)
- } else if let Some(value) = attr.value_str() {
- Ok(Some(OnUnimplementedDirective {
- condition: None,
- message: None,
- subcommands: vec![],
- label: Some(OnUnimplementedFormatString::try_parse(
- tcx,
- item_def_id,
- value,
- attr.span,
- )?),
- note: None,
- parent_label: None,
- append_const_msg: None,
- }))
- } else {
- let reported =
- tcx.sess.delay_span_bug(DUMMY_SP, "of_item: neither meta_item_list nor value_str");
- return Err(reported);
- };
- debug!("of_item({:?}) = {:?}", item_def_id, result);
- result
- }
-
- pub fn evaluate(
- &self,
- tcx: TyCtxt<'tcx>,
- trait_ref: ty::TraitRef<'tcx>,
- options: &[(Symbol, Option<String>)],
- ) -> OnUnimplementedNote {
- let mut message = None;
- let mut label = None;
- let mut note = None;
- let mut parent_label = None;
- let mut append_const_msg = None;
- info!("evaluate({:?}, trait_ref={:?}, options={:?})", self, trait_ref, options);
-
- let options_map: FxHashMap<Symbol, String> =
- options.iter().filter_map(|(k, v)| v.as_ref().map(|v| (*k, v.to_owned()))).collect();
-
- for command in self.subcommands.iter().chain(Some(self)).rev() {
- if let Some(ref condition) = command.condition && !attr::eval_condition(
- condition,
- &tcx.sess.parse_sess,
- Some(tcx.features()),
- &mut |cfg| {
- let value = cfg.value.map(|v| {
- OnUnimplementedFormatString(v).format(tcx, trait_ref, &options_map)
- });
-
- options.contains(&(cfg.name, value))
- },
- ) {
- debug!("evaluate: skipping {:?} due to condition", command);
- continue;
- }
- debug!("evaluate: {:?} succeeded", command);
- if let Some(ref message_) = command.message {
- message = Some(message_.clone());
- }
-
- if let Some(ref label_) = command.label {
- label = Some(label_.clone());
- }
-
- if let Some(ref note_) = command.note {
- note = Some(note_.clone());
- }
-
- if let Some(ref parent_label_) = command.parent_label {
- parent_label = Some(parent_label_.clone());
- }
-
- append_const_msg = command.append_const_msg;
- }
-
- OnUnimplementedNote {
- label: label.map(|l| l.format(tcx, trait_ref, &options_map)),
- message: message.map(|m| m.format(tcx, trait_ref, &options_map)),
- note: note.map(|n| n.format(tcx, trait_ref, &options_map)),
- parent_label: parent_label.map(|e_s| e_s.format(tcx, trait_ref, &options_map)),
- append_const_msg,
- }
- }
-}
-
-impl<'tcx> OnUnimplementedFormatString {
- fn try_parse(
- tcx: TyCtxt<'tcx>,
- item_def_id: DefId,
- from: Symbol,
- err_sp: Span,
- ) -> Result<Self, ErrorGuaranteed> {
- let result = OnUnimplementedFormatString(from);
- result.verify(tcx, item_def_id, err_sp)?;
- Ok(result)
- }
-
- fn verify(
- &self,
- tcx: TyCtxt<'tcx>,
- item_def_id: DefId,
- span: Span,
- ) -> Result<(), ErrorGuaranteed> {
- let trait_def_id = if tcx.is_trait(item_def_id) {
- item_def_id
- } else {
- tcx.trait_id_of_impl(item_def_id)
- .expect("expected `on_unimplemented` to correspond to a trait")
- };
- let trait_name = tcx.item_name(trait_def_id);
- let generics = tcx.generics_of(item_def_id);
- let s = self.0.as_str();
- let parser = Parser::new(s, None, None, false, ParseMode::Format);
- let mut result = Ok(());
- for token in parser {
- match token {
- Piece::String(_) => (), // Normal string, no need to check it
- Piece::NextArgument(a) => match a.position {
- Position::ArgumentNamed(s) => {
- match Symbol::intern(s) {
- // `{Self}` is allowed
- kw::SelfUpper => (),
- // `{ThisTraitsName}` is allowed
- s if s == trait_name => (),
- // `{from_method}` is allowed
- sym::from_method => (),
- // `{from_desugaring}` is allowed
- sym::from_desugaring => (),
- // `{ItemContext}` is allowed
- sym::ItemContext => (),
- // `{integral}` and `{integer}` and `{float}` are allowed
- sym::integral | sym::integer_ | sym::float => (),
- // So is `{A}` if A is a type parameter
- s => match generics.params.iter().find(|param| param.name == s) {
- Some(_) => (),
- None => {
- let reported = struct_span_err!(
- tcx.sess,
- span,
- E0230,
- "there is no parameter `{}` on {}",
- s,
- if trait_def_id == item_def_id {
- format!("trait `{}`", trait_name)
- } else {
- "impl".to_string()
- }
- )
- .emit();
- result = Err(reported);
- }
- },
- }
- }
- // `{:1}` and `{}` are not to be used
- Position::ArgumentIs(..) | Position::ArgumentImplicitlyIs(_) => {
- let reported = struct_span_err!(
- tcx.sess,
- span,
- E0231,
- "only named substitution parameters are allowed"
- )
- .emit();
- result = Err(reported);
- }
- },
- }
- }
-
- result
- }
-
- pub fn format(
- &self,
- tcx: TyCtxt<'tcx>,
- trait_ref: ty::TraitRef<'tcx>,
- options: &FxHashMap<Symbol, String>,
- ) -> String {
- let name = tcx.item_name(trait_ref.def_id);
- let trait_str = tcx.def_path_str(trait_ref.def_id);
- let generics = tcx.generics_of(trait_ref.def_id);
- let generic_map = generics
- .params
- .iter()
- .filter_map(|param| {
- let value = match param.kind {
- GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
- trait_ref.substs[param.index as usize].to_string()
- }
- GenericParamDefKind::Lifetime => return None,
- };
- let name = param.name;
- Some((name, value))
- })
- .collect::<FxHashMap<Symbol, String>>();
- let empty_string = String::new();
-
- let s = self.0.as_str();
- let parser = Parser::new(s, None, None, false, ParseMode::Format);
- let item_context = (options.get(&sym::ItemContext)).unwrap_or(&empty_string);
- parser
- .map(|p| match p {
- Piece::String(s) => s,
- Piece::NextArgument(a) => match a.position {
- Position::ArgumentNamed(s) => {
- let s = Symbol::intern(s);
- match generic_map.get(&s) {
- Some(val) => val,
- None if s == name => &trait_str,
- None => {
- if let Some(val) = options.get(&s) {
- val
- } else if s == sym::from_desugaring || s == sym::from_method {
- // don't break messages using these two arguments incorrectly
- &empty_string
- } else if s == sym::ItemContext {
- &item_context
- } else if s == sym::integral {
- "{integral}"
- } else if s == sym::integer_ {
- "{integer}"
- } else if s == sym::float {
- "{float}"
- } else {
- bug!(
- "broken on_unimplemented {:?} for {:?}: \
- no argument matching {:?}",
- self.0,
- trait_ref,
- s
- )
- }
- }
- }
- }
- _ => bug!("broken on_unimplemented {:?} - bad format arg", self.0),
- },
- })
- .collect()
- }
-}
use crate::infer::InferCtxt;
use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput};
use crate::traits::query::NoSolution;
-use crate::traits::{ObligationCause, TraitEngine, TraitEngineExt};
+use crate::traits::ObligationCause;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_hir::HirId;
debug!(?constraints);
// Instantiation may have produced new inference variables and constraints on those
// variables. Process these constraints.
- let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new(self.tcx);
let cause = ObligationCause::misc(span, body_id);
- for &constraint in &constraints.outlives {
- let obligation = self.query_outlives_constraint_to_obligation(
- constraint,
- cause.clone(),
- param_env,
- );
- fulfill_cx.register_predicate_obligation(self, obligation);
- }
+ let errors = super::fully_solve_obligations(
+ self,
+ constraints.outlives.iter().map(|constraint| {
+ self.query_outlives_constraint_to_obligation(
+ *constraint,
+ cause.clone(),
+ param_env,
+ )
+ }),
+ );
if !constraints.member_constraints.is_empty() {
span_bug!(span, "{:#?}", constraints.member_constraints);
}
- let errors = fulfill_cx.select_all_or_error(self);
if !errors.is_empty() {
self.tcx.sess.delay_span_bug(
span,
#[instrument(skip(self), level = "debug")]
fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> {
let tcx = self.selcx.tcx();
- if tcx.lazy_normalization() {
+ if tcx.lazy_normalization() || !needs_normalization(&constant, self.param_env.reveal()) {
constant
} else {
let constant = constant.super_fold_with(self);
let universe = self.universe_for(debruijn);
let p = ty::PlaceholderConst { universe, name: bound_const };
self.mapped_consts.insert(p, bound_const);
- self.infcx
- .tcx
- .mk_const(ty::ConstS { kind: ty::ConstKind::Placeholder(p), ty: ct.ty() })
+ self.infcx.tcx.mk_const(ty::ConstKind::Placeholder(p), ct.ty())
}
_ => ct.super_fold_with(self),
}
let db = ty::DebruijnIndex::from_usize(
self.universe_indices.len() - index + self.current_index.as_usize() - 1,
);
- self.tcx().mk_const(ty::ConstS {
- kind: ty::ConstKind::Bound(db, *replace_var),
- ty: ct.ty(),
- })
+ self.tcx().mk_const(ty::ConstKind::Bound(db, *replace_var), ct.ty())
}
None => ct,
}
crate::traits::InternalSubsts::identity_for_item(tcx, assoc_ty.item.def_id);
let did = ty::WithOptConstParam::unknown(assoc_ty.item.def_id);
let kind = ty::ConstKind::Unevaluated(ty::UnevaluatedConst::new(did, identity_substs));
- ty.map_bound(|ty| tcx.mk_const(ty::ConstS { ty, kind }).into())
+ ty.map_bound(|ty| tcx.mk_const(kind, ty).into())
} else {
ty.map_bound(|ty| ty.into())
};
// Verify that the trait item and its implementation have compatible substs lists
fn check_substs_compatible<'tcx>(
tcx: TyCtxt<'tcx>,
- assoc_ty: &ty::AssocItem,
+ assoc_item: &ty::AssocItem,
substs: ty::SubstsRef<'tcx>,
) -> bool {
fn check_substs_compatible_inner<'tcx>(
true
}
- check_substs_compatible_inner(tcx, tcx.generics_of(assoc_ty.def_id), substs.as_slice())
+ let generics = tcx.generics_of(assoc_item.def_id);
+ // Chop off any additional substs (RPITIT) substs
+ let substs = &substs[0..generics.count().min(substs.len())];
+ check_substs_compatible_inner(tcx, generics, substs)
}
fn confirm_impl_trait_in_trait_candidate<'tcx>(
};
}
- let impl_fn_def_id = leaf_def.item.def_id;
// Rebase from {trait}::{fn}::{opaque} to {impl}::{fn}::{opaque},
// since `data.substs` are the impl substs.
let impl_fn_substs =
obligation.predicate.substs.rebase_onto(tcx, tcx.parent(trait_fn_def_id), data.substs);
+ let impl_fn_substs = translate_substs(
+ selcx.infcx(),
+ obligation.param_env,
+ data.impl_def_id,
+ impl_fn_substs,
+ leaf_def.defining_node,
+ );
+
+ if !check_substs_compatible(tcx, &leaf_def.item, impl_fn_substs) {
+ let err = tcx.ty_error_with_message(
+ obligation.cause.span,
+ "impl method and trait method have different parameters",
+ );
+ return Progress { term: err.into(), obligations };
+ }
+
+ let impl_fn_def_id = leaf_def.item.def_id;
let cause = ObligationCause::new(
obligation.cause.span,
&mut self,
constant: ty::Const<'tcx>,
) -> Result<ty::Const<'tcx>, Self::Error> {
+ if !needs_normalization(&constant, self.param_env.reveal()) {
+ return Ok(constant);
+ }
+
let constant = constant.try_super_fold_with(self)?;
debug!(?constant, ?self.param_env);
Ok(crate::traits::project::with_replaced_escaping_bound_vars(
use crate::traits::coherence::Conflict;
use crate::traits::query::evaluate_obligation::InferCtxtExt;
use crate::traits::{util, SelectionResult};
-use crate::traits::{Ambiguous, ErrorReporting, Overflow, Unimplemented};
+use crate::traits::{ErrorReporting, Overflow, Unimplemented};
use super::BuiltinImplConditions;
use super::IntercrateAmbiguityCause;
// and report ambiguity.
if i > 1 {
debug!("multiple matches, ambig");
- return Err(Ambiguous(
- candidates
- .into_iter()
- .filter_map(|c| match c.candidate {
- SelectionCandidate::ImplCandidate(def_id) => Some(def_id),
- _ => None,
- })
- .collect(),
- ));
+ return Ok(None);
}
}
}
GenericParamDefKind::Const { .. } => {
let bound_var = ty::BoundVariableKind::Const;
bound_vars.push(bound_var);
- tcx.mk_const(ty::ConstS {
- ty: tcx.type_of(param.def_id),
- kind: ty::ConstKind::Bound(
+ tcx.mk_const(
+ ty::ConstKind::Bound(
ty::INNERMOST,
ty::BoundVar::from_usize(bound_vars.len() - 1),
),
- })
+ tcx.type_of(param.def_id),
+ )
.into()
}
});
assert!(self.query_mode == TraitQueryMode::Canonical);
return Err(SelectionError::Overflow(OverflowError::Canonical));
}
- Err(SelectionError::Ambiguous(_)) => {
- return Ok(None);
- }
Err(e) => {
return Err(e);
}
match self.candidate_from_obligation(stack) {
Ok(Some(c)) => self.evaluate_candidate(stack, &c),
- Err(SelectionError::Ambiguous(_)) => Ok(EvaluatedToAmbig),
Ok(None) => Ok(EvaluatedToAmbig),
Err(Overflow(OverflowError::Canonical)) => Err(OverflowError::Canonical),
Err(ErrorReporting) => Err(OverflowError::ErrorReporting),
/// filter_impls filters constant trait obligations and candidates that have a positive impl
/// for a negative goal and a negative impl for a positive goal
- #[instrument(level = "debug", skip(self))]
+ #[instrument(level = "debug", skip(self, candidates))]
fn filter_impls(
&mut self,
candidates: Vec<SelectionCandidate<'tcx>>,
obligation: &TraitObligation<'tcx>,
) -> Vec<SelectionCandidate<'tcx>> {
+ trace!("{candidates:#?}");
let tcx = self.tcx();
let mut result = Vec::with_capacity(candidates.len());
}
}
+ trace!("{result:#?}");
result
}
/// Bar<i32> where struct Bar<T> { x: T, y: u32 } -> [i32, u32]
/// Zed<i32> where enum Zed { A(T), B(u32) } -> [i32, u32]
/// ```
+ #[instrument(level = "debug", skip(self), ret)]
fn constituent_types_for_ty(
&self,
t: ty::Binder<'tcx, Ty<'tcx>>,
trait_ref, item, cause, pred
);
let (items, impl_def_id) = match item {
- Some(hir::Item { kind: hir::ItemKind::Impl(impl_), def_id, .. }) => (impl_.items, *def_id),
+ Some(hir::Item { kind: hir::ItemKind::Impl(impl_), owner_id, .. }) => {
+ (impl_.items, *owner_id)
+ }
_ => return,
};
let fix_span =
tcx.impl_item_implementor_ids(impl_def_id).get(&projection_ty.item_def_id)
&& let Some(impl_item_span) = items
.iter()
- .find(|item| item.id.def_id.to_def_id() == impl_item_id)
+ .find(|item| item.id.owner_id.to_def_id() == impl_item_id)
.map(fix_span)
{
cause.span = impl_item_span;
tcx.impl_item_implementor_ids(impl_def_id).get(&item_def_id)
&& let Some(impl_item_span) = items
.iter()
- .find(|item| item.id.def_id.to_def_id() == impl_item_id)
+ .find(|item| item.id.owner_id.to_def_id() == impl_item_id)
.map(fix_span)
{
cause.span = impl_item_span;
let obligations = if trait_pred.constness == ty::BoundConstness::NotConst {
self.nominal_obligations_without_const(trait_ref.def_id, trait_ref.substs)
} else {
- if !tcx.has_attr(trait_ref.def_id, rustc_span::sym::const_trait) {
- if let Some(item) = self.item &&
- let hir::ItemKind::Impl(impl_) = item.kind &&
- let Some(trait_) = &impl_.of_trait &&
- let Some(def_id) = trait_.trait_def_id() &&
- def_id == trait_ref.def_id
- {
- let trait_name = tcx.item_name(def_id);
- let mut err = tcx.sess.struct_span_err(
- self.span,
- &format!("const `impl` for trait `{trait_name}` which is not marked with `#[const_trait]`"),
- );
- if def_id.is_local() {
- let sp = tcx.def_span(def_id).shrink_to_lo();
- err.span_suggestion(sp, &format!("mark `{trait_name}` as const"), "#[const_trait]", rustc_errors::Applicability::MachineApplicable);
- }
- err.note("marking a trait with `#[const_trait]` ensures all default method bodies are `const`");
- err.note("adding a non-const method body in the future would be a breaking change");
- err.emit();
- } else {
- tcx.sess.span_err(
- self.span,
- "~const can only be applied to `#[const_trait]` traits",
- );
- }
- }
self.nominal_obligations(trait_ref.def_id, trait_ref.substs)
};
}
ty::FnDef(did, substs) => {
- let obligations = self.nominal_obligations(did, substs);
+ let obligations = self.nominal_obligations_without_const(did, substs);
self.out.extend(obligations);
}
ty::GenericParamDefKind::Lifetime => {
let br = ty::BoundRegion {
var: ty::BoundVar::from_usize(substs.len()),
- kind: ty::BrAnon(substs.len() as u32),
+ kind: ty::BrAnon(substs.len() as u32, None),
};
tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)).into()
}
ty::GenericParamDefKind::Const { .. } => tcx
- .mk_const(ty::ConstS {
- kind: ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from(param.index)),
- ty: tcx.type_of(param.def_id),
- })
+ .mk_const(
+ ty::ConstKind::Bound(ty::INNERMOST, ty::BoundVar::from(param.index)),
+ tcx.type_of(param.def_id),
+ )
.into(),
})
}
ty::DebruijnIndex::from_u32(var.debruijn.depth()),
ty::BoundRegion {
var: ty::BoundVar::from_usize(var.index),
- kind: ty::BrAnon(var.index as u32),
+ kind: ty::BrAnon(var.index as u32, None),
},
),
chalk_ir::LifetimeData::InferenceVar(_var) => unimplemented!(),
chalk_ir::LifetimeData::Placeholder(p) => ty::RePlaceholder(ty::Placeholder {
universe: ty::UniverseIndex::from_usize(p.ui.counter),
- name: ty::BoundRegionKind::BrAnon(p.idx as u32),
+ name: ty::BoundRegionKind::BrAnon(p.idx as u32, None),
}),
chalk_ir::LifetimeData::Static => return interner.tcx.lifetimes.re_static,
chalk_ir::LifetimeData::Empty(_) => {
chalk_ir::ConstValue::Placeholder(_p) => unimplemented!(),
chalk_ir::ConstValue::Concrete(c) => ty::ConstKind::Value(c.interned),
};
- interner.tcx.mk_const(ty::ConstS { ty, kind })
+ interner.tcx.mk_const(kind, ty)
}
}
}
}
- ty::BoundRegionKind::BrAnon(var) => match self.parameters.entry(var) {
+ ty::BoundRegionKind::BrAnon(var, _) => match self.parameters.entry(var) {
Entry::Vacant(entry) => {
entry.insert(chalk_ir::VariableKind::Lifetime);
}
ty::ReLateBound(index, br) if index == self.binder_index => match br.kind {
ty::BrNamed(def_id, _name) => match self.named_parameters.get(&def_id) {
Some(idx) => {
- let new_br = ty::BoundRegion { var: br.var, kind: ty::BrAnon(*idx) };
+ let new_br = ty::BoundRegion { var: br.var, kind: ty::BrAnon(*idx, None) };
return self.tcx.mk_region(ty::ReLateBound(index, new_br));
}
None => panic!("Missing `BrNamed`."),
},
ty::BrEnv => unimplemented!(),
- ty::BrAnon(_) => {}
+ ty::BrAnon(..) => {}
},
_ => (),
};
Some(idx) => {
let br = ty::BoundRegion {
var: ty::BoundVar::from_u32(*idx),
- kind: ty::BrAnon(*idx),
+ kind: ty::BrAnon(*idx, None),
};
self.tcx.mk_region(ty::ReLateBound(self.binder_index, br))
}
None => {
let idx = self.named_regions.len() as u32;
- let br =
- ty::BoundRegion { var: ty::BoundVar::from_u32(idx), kind: ty::BrAnon(idx) };
+ let br = ty::BoundRegion {
+ var: ty::BoundVar::from_u32(idx),
+ kind: ty::BrAnon(idx, None),
+ };
self.named_regions.insert(_re.def_id, idx);
self.tcx.mk_region(ty::ReLateBound(self.binder_index, br))
}
fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> {
match *r {
ty::RePlaceholder(p) if p.universe == self.universe_index => {
- if let ty::BoundRegionKind::BrAnon(anon) = p.name {
+ if let ty::BoundRegionKind::BrAnon(anon, _) = p.name {
self.next_anon_region_placeholder = self.next_anon_region_placeholder.max(anon);
}
}
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, Vec<OutlivesBound<'tcx>>>>,
NoSolution,
> {
- tcx.infer_ctxt().enter_canonical_trait_query(&goal, |infcx, _fulfill_cx, key| {
+ tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| {
let (param_env, ty) = key.into_parts();
- compute_implied_outlives_bounds(&infcx, param_env, ty)
+ compute_implied_outlives_bounds(&ocx.infcx, param_env, ty)
})
}
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
+#![feature(let_chains)]
#![recursion_limit = "256"]
#[macro_use]
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
use rustc_infer::infer::TyCtxtInferExt;
-use rustc_infer::traits::TraitEngineExt as _;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
use rustc_trait_selection::infer::InferCtxtBuilderExt;
tcx.sess.perf_stats.normalize_projection_ty.fetch_add(1, Ordering::Relaxed);
tcx.infer_ctxt().enter_canonical_trait_query(
&goal,
- |infcx, fulfill_cx, ParamEnvAnd { param_env, value: goal }| {
- let selcx = &mut SelectionContext::new(infcx);
+ |ocx, ParamEnvAnd { param_env, value: goal }| {
+ let selcx = &mut SelectionContext::new(ocx.infcx);
let cause = ObligationCause::dummy();
let mut obligations = vec![];
let answer = traits::normalize_projection_type(
0,
&mut obligations,
);
- fulfill_cx.register_predicate_obligations(infcx, obligations);
+ ocx.register_obligations(obligations);
// FIXME(associated_const_equality): All users of normalize_projection_ty expected
// a type, but there is the possibility it could've been a const now. Maybe change
// it to a Term later?
use rustc_hir::def_id::DefId;
use rustc_infer::infer::at::ToTrace;
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
-use rustc_infer::infer::{DefiningAnchor, InferCtxt, TyCtxtInferExt};
-use rustc_infer::traits::{ObligationCauseCode, TraitEngineExt as _};
+use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt};
+use rustc_infer::traits::ObligationCauseCode;
use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{
- self, EarlyBinder, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable, Variance,
-};
-use rustc_middle::ty::{GenericArg, UserSelfTy, UserSubsts};
-use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Predicate, ToPredicate};
+use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{ParamEnvAnd, Predicate, ToPredicate};
+use rustc_middle::ty::{UserSelfTy, UserSubsts};
use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::infer::InferCtxtBuilderExt;
-use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::query::normalize::AtExt;
use rustc_trait_selection::traits::query::type_op::ascribe_user_type::AscribeUserType;
use rustc_trait_selection::traits::query::type_op::eq::Eq;
use rustc_trait_selection::traits::query::type_op::prove_predicate::ProvePredicate;
use rustc_trait_selection::traits::query::type_op::subtype::Subtype;
use rustc_trait_selection::traits::query::{Fallible, NoSolution};
-use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, TraitEngine};
+use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, ObligationCtxt};
use std::fmt;
use std::iter::zip;
tcx: TyCtxt<'tcx>,
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, AscribeUserType<'tcx>>>,
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> {
- tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
- type_op_ascribe_user_type_with_span(infcx, fulfill_cx, key, None)
+ tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |ocx, key| {
+ type_op_ascribe_user_type_with_span(ocx, key, None)
})
}
/// The core of the `type_op_ascribe_user_type` query: for diagnostics purposes in NLL HRTB errors,
/// this query can be re-run to better track the span of the obligation cause, and improve the error
/// message. Do not call directly unless you're in that very specific context.
-pub fn type_op_ascribe_user_type_with_span<'a, 'tcx: 'a>(
- infcx: &'a InferCtxt<'tcx>,
- fulfill_cx: &'a mut dyn TraitEngine<'tcx>,
+pub fn type_op_ascribe_user_type_with_span<'tcx>(
+ ocx: &ObligationCtxt<'_, 'tcx>,
key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>,
span: Option<Span>,
) -> Result<(), NoSolution> {
"type_op_ascribe_user_type: mir_ty={:?} def_id={:?} user_substs={:?}",
mir_ty, def_id, user_substs
);
-
- let mut cx = AscribeUserTypeCx { infcx, param_env, span: span.unwrap_or(DUMMY_SP), fulfill_cx };
+ let cx = AscribeUserTypeCx { ocx, param_env, span: span.unwrap_or(DUMMY_SP) };
cx.relate_mir_and_user_ty(mir_ty, def_id, user_substs)?;
Ok(())
}
struct AscribeUserTypeCx<'me, 'tcx> {
- infcx: &'me InferCtxt<'tcx>,
- param_env: ParamEnv<'tcx>,
+ ocx: &'me ObligationCtxt<'me, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
span: Span,
- fulfill_cx: &'me mut dyn TraitEngine<'tcx>,
}
impl<'me, 'tcx> AscribeUserTypeCx<'me, 'tcx> {
- fn normalize<T>(&mut self, value: T) -> T
+ fn normalize<T>(&self, value: T) -> T
where
T: TypeFoldable<'tcx>,
{
self.normalize_with_cause(value, ObligationCause::misc(self.span, hir::CRATE_HIR_ID))
}
- fn normalize_with_cause<T>(&mut self, value: T, cause: ObligationCause<'tcx>) -> T
+ fn normalize_with_cause<T>(&self, value: T, cause: ObligationCause<'tcx>) -> T
where
T: TypeFoldable<'tcx>,
{
- self.infcx
- .partially_normalize_associated_types_in(cause, self.param_env, value)
- .into_value_registering_obligations(self.infcx, self.fulfill_cx)
+ self.ocx.normalize(cause, self.param_env, value)
}
- fn relate<T>(&mut self, a: T, variance: Variance, b: T) -> Result<(), NoSolution>
+ fn eq<T>(&self, a: T, b: T) -> Result<(), NoSolution>
where
T: ToTrace<'tcx>,
{
- self.infcx
- .at(&ObligationCause::dummy_with_span(self.span), self.param_env)
- .relate(a, variance, b)?
- .into_value_registering_obligations(self.infcx, self.fulfill_cx);
- Ok(())
+ Ok(self.ocx.eq(&ObligationCause::dummy_with_span(self.span), self.param_env, a, b)?)
}
- fn prove_predicate(&mut self, predicate: Predicate<'tcx>, cause: ObligationCause<'tcx>) {
- self.fulfill_cx.register_predicate_obligation(
- self.infcx,
- Obligation::new(cause, self.param_env, predicate),
- );
+ fn prove_predicate(&self, predicate: Predicate<'tcx>, cause: ObligationCause<'tcx>) {
+ self.ocx.register_obligation(Obligation::new(cause, self.param_env, predicate));
}
fn tcx(&self) -> TyCtxt<'tcx> {
- self.infcx.tcx
- }
-
- fn subst<T>(&self, value: T, substs: &[GenericArg<'tcx>]) -> T
- where
- T: TypeFoldable<'tcx>,
- {
- EarlyBinder(value).subst(self.tcx(), substs)
+ self.ocx.infcx.tcx
}
#[instrument(level = "debug", skip(self))]
fn relate_mir_and_user_ty(
- &mut self,
+ &self,
mir_ty: Ty<'tcx>,
def_id: DefId,
user_substs: UserSubsts<'tcx>,
let UserSubsts { user_self_ty, substs } = user_substs;
let tcx = self.tcx();
- let ty = tcx.type_of(def_id);
- let ty = self.subst(ty, substs);
+ let ty = tcx.bound_type_of(def_id).subst(tcx, substs);
let ty = self.normalize(ty);
debug!("relate_type_and_user_type: ty of def-id is {:?}", ty);
- self.relate(mir_ty, Variance::Invariant, ty)?;
+ self.eq(mir_ty, ty)?;
// Prove the predicates coming along with `def_id`.
//
// Also, normalize the `instantiated_predicates`
// because otherwise we wind up with duplicate "type
// outlives" error messages.
- let instantiated_predicates =
- self.tcx().predicates_of(def_id).instantiate(self.tcx(), substs);
+ let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs);
let cause = ObligationCause::dummy_with_span(self.span);
}
if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
- let impl_self_ty = self.tcx().type_of(impl_def_id);
- let impl_self_ty = self.subst(impl_self_ty, &substs);
+ let impl_self_ty = tcx.bound_type_of(impl_def_id).subst(tcx, substs);
let impl_self_ty = self.normalize(impl_self_ty);
- self.relate(self_ty, Variance::Invariant, impl_self_ty)?;
+ self.eq(self_ty, impl_self_ty)?;
self.prove_predicate(
ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into()))
- .to_predicate(self.tcx()),
+ .to_predicate(tcx),
cause.clone(),
);
}
// type were ill-formed but did not appear in `ty`,
// which...could happen with normalization...
self.prove_predicate(
- ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())).to_predicate(self.tcx()),
+ ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())).to_predicate(tcx),
cause,
);
Ok(())
tcx: TyCtxt<'tcx>,
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Eq<'tcx>>>,
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> {
- tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
+ tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |ocx, key| {
let (param_env, Eq { a, b }) = key.into_parts();
- infcx
- .at(&ObligationCause::dummy(), param_env)
- .eq(a, b)?
- .into_value_registering_obligations(infcx, fulfill_cx);
- Ok(())
+ Ok(ocx.eq(&ObligationCause::dummy(), param_env, a, b)?)
})
}
fn type_op_normalize<'tcx, T>(
- infcx: &InferCtxt<'tcx>,
- fulfill_cx: &mut dyn TraitEngine<'tcx>,
+ ocx: &ObligationCtxt<'_, 'tcx>,
key: ParamEnvAnd<'tcx, Normalize<T>>,
) -> Fallible<T>
where
{
let (param_env, Normalize { value }) = key.into_parts();
let Normalized { value, obligations } =
- infcx.at(&ObligationCause::dummy(), param_env).normalize(value)?;
- fulfill_cx.register_predicate_obligations(infcx, obligations);
+ ocx.infcx.at(&ObligationCause::dummy(), param_env).normalize(value)?;
+ ocx.register_obligations(obligations);
Ok(value)
}
tcx: TyCtxt<'tcx>,
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Subtype<'tcx>>>,
) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> {
- tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
+ tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |ocx, key| {
let (param_env, Subtype { sub, sup }) = key.into_parts();
- infcx
- .at(&ObligationCause::dummy(), param_env)
- .sup(sup, sub)?
- .into_value_registering_obligations(infcx, fulfill_cx);
- Ok(())
+ Ok(ocx.sup(&ObligationCause::dummy(), param_env, sup, sub)?)
})
}
// impl-trait/issue-99642.rs
tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bubble).enter_canonical_trait_query(
&canonicalized,
- |infcx, fulfill_cx, key| {
- type_op_prove_predicate_with_cause(infcx, fulfill_cx, key, ObligationCause::dummy());
+ |ocx, key| {
+ type_op_prove_predicate_with_cause(ocx, key, ObligationCause::dummy());
Ok(())
},
)
/// The core of the `type_op_prove_predicate` query: for diagnostics purposes in NLL HRTB errors,
/// this query can be re-run to better track the span of the obligation cause, and improve the error
/// message. Do not call directly unless you're in that very specific context.
-pub fn type_op_prove_predicate_with_cause<'a, 'tcx: 'a>(
- infcx: &'a InferCtxt<'tcx>,
- fulfill_cx: &'a mut dyn TraitEngine<'tcx>,
+pub fn type_op_prove_predicate_with_cause<'tcx>(
+ ocx: &ObligationCtxt<'_, 'tcx>,
key: ParamEnvAnd<'tcx, ProvePredicate<'tcx>>,
cause: ObligationCause<'tcx>,
) {
let (param_env, ProvePredicate { predicate }) = key.into_parts();
- fulfill_cx.register_predicate_obligation(infcx, Obligation::new(cause, param_env, predicate));
+ ocx.register_obligation(Obligation::new(cause, param_env, predicate));
}
}
ty::Array(ty, len) => {
- let len = len.try_eval_usize(tcx, ParamEnv::reveal_all()).unwrap();
+ let len =
+ len.try_eval_usize(tcx, ParamEnv::reveal_all()).ok_or(Err::Unspecified)?;
let elt = Tree::from_ty(*ty, tcx)?;
Ok(std::iter::repeat(elt)
.take(len as usize)
// finally: padding
let padding_span = trace_span!("adding trailing padding").entered();
- let padding_needed = layout_summary.total_size - variant_layout.size();
- if padding_needed > 0 {
+ if layout_summary.total_size > variant_layout.size() {
+ let padding_needed = layout_summary.total_size - variant_layout.size();
tree = tree.then(Self::padding(padding_needed));
};
drop(padding_span);
let c = c.eval(tcx, param_env);
- if let Some(err) = c.error_reported() {
+ if let Err(err) = c.error_reported() {
return Some(Self {
alignment: true,
lifetimes: true,
let item = tcx.hir().expect_item(def_id.expect_local());
match item.kind {
hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter(
- trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.def_id.to_def_id()),
+ trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.owner_id.to_def_id()),
),
hir::ItemKind::Impl(ref impl_) => tcx.arena.alloc_from_iter(
- impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.def_id.to_def_id()),
+ impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.owner_id.to_def_id()),
),
hir::ItemKind::TraitAlias(..) => &[],
_ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
match parent_item.kind {
hir::ItemKind::Impl(ref impl_) => {
if let Some(impl_item_ref) =
- impl_.items.iter().find(|i| i.id.def_id.to_def_id() == def_id)
+ impl_.items.iter().find(|i| i.id.owner_id.to_def_id() == def_id)
{
let assoc_item = associated_item_from_impl_item_ref(impl_item_ref);
debug_assert_eq!(assoc_item.def_id, def_id);
hir::ItemKind::Trait(.., ref trait_item_refs) => {
if let Some(trait_item_ref) =
- trait_item_refs.iter().find(|i| i.id.def_id.to_def_id() == def_id)
+ trait_item_refs.iter().find(|i| i.id.owner_id.to_def_id() == def_id)
{
let assoc_item = associated_item_from_trait_item_ref(trait_item_ref);
debug_assert_eq!(assoc_item.def_id, def_id);
}
fn associated_item_from_trait_item_ref(trait_item_ref: &hir::TraitItemRef) -> ty::AssocItem {
- let def_id = trait_item_ref.id.def_id;
+ let owner_id = trait_item_ref.id.owner_id;
let (kind, has_self) = match trait_item_ref.kind {
hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
ty::AssocItem {
name: trait_item_ref.ident.name,
kind,
- def_id: def_id.to_def_id(),
- trait_item_def_id: Some(def_id.to_def_id()),
+ def_id: owner_id.to_def_id(),
+ trait_item_def_id: Some(owner_id.to_def_id()),
container: ty::TraitContainer,
fn_has_self_parameter: has_self,
}
}
fn associated_item_from_impl_item_ref(impl_item_ref: &hir::ImplItemRef) -> ty::AssocItem {
- let def_id = impl_item_ref.id.def_id;
+ let def_id = impl_item_ref.id.owner_id;
let (kind, has_self) = match impl_item_ref.kind {
hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
// construct the consts for the elements of the array/slice
let field_consts = branches
.iter()
- .map(|b| tcx.mk_const(ty::ConstS { kind: ty::ConstKind::Value(*b), ty: *inner_ty }))
+ .map(|b| tcx.mk_const(ty::ConstKind::Value(*b), *inner_ty))
.collect::<Vec<_>>();
debug!(?field_consts);
for (field, field_valtree) in iter::zip(fields, branches) {
let field_ty = field.ty(tcx, substs);
- let field_const = tcx.mk_const(ty::ConstS {
- kind: ty::ConstKind::Value(*field_valtree),
- ty: field_ty,
- });
+ let field_const = tcx.mk_const(ty::ConstKind::Value(*field_valtree), field_ty);
field_consts.push(field_const);
}
debug!(?field_consts);
ty::Tuple(elem_tys) => {
let fields = iter::zip(*elem_tys, branches)
.map(|(elem_ty, elem_valtree)| {
- tcx.mk_const(ty::ConstS {
- kind: ty::ConstKind::Value(*elem_valtree),
- ty: elem_ty,
- })
+ tcx.mk_const(ty::ConstKind::Value(*elem_valtree), elem_ty)
})
.collect::<Vec<_>>();
let uneval =
ty::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs);
- let constant = self
- .tcx
- .mk_const(ty::ConstS { kind: ty::ConstKind::Unevaluated(uneval), ty: node.ty });
+ let constant = self.tcx.mk_const(ty::ConstKind::Unevaluated(uneval), node.ty);
self.nodes.push(Node::Leaf(constant))
}
ExprKind::ConstParam { param, .. } => {
- let const_param = self
- .tcx
- .mk_const(ty::ConstS { kind: ty::ConstKind::Param(*param), ty: node.ty });
+ let const_param = self.tcx.mk_const(ty::ConstKind::Param(*param), node.ty);
self.nodes.push(Node::Leaf(const_param))
}
use rustc_middle::traits::CodegenObligationError;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, Instance, TyCtxt, TypeVisitable};
-use rustc_span::{sym, DUMMY_SP};
+use rustc_span::sym;
use rustc_trait_selection::traits;
use traits::{translate_substs, Reveal};
if name == sym::clone {
let self_ty = trait_ref.self_ty();
- let is_copy = self_ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env);
+ let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env);
match self_ty.kind() {
_ if is_copy => (),
ty::Generator(..)
}
let pointee = tcx.normalize_erasing_regions(param_env, pointee);
- if pointee.is_sized(tcx.at(DUMMY_SP), param_env) {
+ if pointee.is_sized(tcx, param_env) {
return Ok(tcx.intern_layout(LayoutS::scalar(cx, data_ptr)));
}
} else {
let param_env = tcx.param_env(def.did());
let last_field = def.variant(v).fields.last().unwrap();
- let always_sized =
- tcx.type_of(last_field.did).is_sized(tcx.at(DUMMY_SP), param_env);
+ let always_sized = tcx.type_of(last_field.did).is_sized(tcx, param_env);
if !always_sized { StructKind::MaybeUnsized } else { StructKind::AlwaysSized }
};
for component in components {
match *component.kind() {
- _ if component.is_copy_modulo_regions(tcx.at(DUMMY_SP), self.param_env) => (),
+ _ if component.is_copy_modulo_regions(tcx, self.param_env) => (),
ty::Closure(_, substs) => {
queue_type(self, substs.as_closure().tupled_upvars_ty());
/// Check if a function is async.
fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
let node = tcx.hir().get_by_def_id(def_id.expect_local());
- if let Some(fn_kind) = node.fn_kind() { fn_kind.asyncness() } else { hir::IsAsync::NotAsync }
+ node.fn_sig().map_or(hir::IsAsync::NotAsync, |sig| sig.header.asyncness)
}
/// Don't call this directly: use ``tcx.conservative_is_privately_uninhabited`` instead.
type BoundTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
type PlaceholderType: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
type InferTy: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
- type DelaySpanBugEmitted: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
+ type ErrorGuaranteed: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
type PredicateKind: Clone + Debug + Hash + PartialEq + Eq;
type AllocId: Clone + Debug + Hash + PartialEq + Eq + PartialOrd + Ord;
/// A placeholder for a type which could not be computed; this is
/// propagated to avoid useless error messages.
- Error(I::DelaySpanBugEmitted),
+ Error(I::ErrorGuaranteed),
}
impl<I: Interner> TyKind<I> {
// This is manually implemented because a derive would require `I: Encodable`
impl<I: Interner, E: TyEncoder> Encodable<E> for TyKind<I>
where
- I::DelaySpanBugEmitted: Encodable<E>,
+ I::ErrorGuaranteed: Encodable<E>,
I::AdtDef: Encodable<E>,
I::SubstsRef: Encodable<E>,
I::DefId: Encodable<E>,
I::BoundTy: Encodable<E>,
I::PlaceholderType: Encodable<E>,
I::InferTy: Encodable<E>,
- I::DelaySpanBugEmitted: Encodable<E>,
I::PredicateKind: Encodable<E>,
I::AllocId: Encodable<E>,
{
// This is manually implemented because a derive would require `I: Decodable`
impl<I: Interner, D: TyDecoder<I = I>> Decodable<D> for TyKind<I>
where
- I::DelaySpanBugEmitted: Decodable<D>,
+ I::ErrorGuaranteed: Decodable<D>,
I::AdtDef: Decodable<D>,
I::SubstsRef: Decodable<D>,
I::DefId: Decodable<D>,
I::BoundTy: Decodable<D>,
I::PlaceholderType: Decodable<D>,
I::InferTy: Decodable<D>,
- I::DelaySpanBugEmitted: Decodable<D>,
I::PredicateKind: Decodable<D>,
I::AllocId: Decodable<D>,
{
I::ParamTy: HashStable<CTX>,
I::PlaceholderType: HashStable<CTX>,
I::InferTy: HashStable<CTX>,
- I::DelaySpanBugEmitted: HashStable<CTX>,
+ I::ErrorGuaranteed: HashStable<CTX>,
{
#[inline]
fn hash_stable(
# on this runtime, such as `-C profile-generate` or `-C instrument-coverage`).
#profiler = false
-# Use the optimized LLVM C intrinsics for `compiler_builtins`, rather than Rust intrinsics.
-# Requires the LLVM submodule to be managed by bootstrap (i.e. not external).
-#optimized-compiler-builtins = false
-
# Indicates whether the native libraries linked into Cargo will be statically
# linked or not.
#cargo-native-static = false
#[allow(unused_attributes)]
#[unstable(feature = "alloc_internals", issue = "none")]
pub mod __alloc_error_handler {
- use crate::alloc::Layout;
-
- // called via generated `__rust_alloc_error_handler`
-
- // if there is no `#[alloc_error_handler]`
+ // called via generated `__rust_alloc_error_handler` if there is no
+ // `#[alloc_error_handler]`.
#[rustc_std_internal_symbol]
pub unsafe fn __rdl_oom(size: usize, _align: usize) -> ! {
panic!("memory allocation of {size} bytes failed")
}
- // if there is an `#[alloc_error_handler]`
+ #[cfg(bootstrap)]
#[rustc_std_internal_symbol]
pub unsafe fn __rg_oom(size: usize, align: usize) -> ! {
+ use crate::alloc::Layout;
+
let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
extern "Rust" {
#[lang = "oom"]
}
#[bench]
-#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
fn alloc_owned_small(b: &mut Bencher) {
b.iter(|| {
let _: Box<_> = Box::new(10);
#[cfg(not(no_global_oom_handling))]
use core::iter::FromIterator;
use core::iter::{FusedIterator, Iterator};
+#[cfg(not(bootstrap))]
+use core::marker::Tuple;
use core::marker::{Destruct, Unpin, Unsize};
use core::mem;
use core::ops::{
#[stable(feature = "fused", since = "1.26.0")]
impl<I: FusedIterator + ?Sized, A: Allocator> FusedIterator for Box<I, A> {}
+#[cfg(bootstrap)]
#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
impl<Args, F: FnOnce<Args> + ?Sized, A: Allocator> FnOnce<Args> for Box<F, A> {
type Output = <F as FnOnce<Args>>::Output;
}
}
+#[cfg(not(bootstrap))]
+#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
+impl<Args: Tuple, F: FnOnce<Args> + ?Sized, A: Allocator> FnOnce<Args> for Box<F, A> {
+ type Output = <F as FnOnce<Args>>::Output;
+
+ extern "rust-call" fn call_once(self, args: Args) -> Self::Output {
+ <F as FnOnce<Args>>::call_once(*self, args)
+ }
+}
+
+#[cfg(bootstrap)]
#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
impl<Args, F: FnMut<Args> + ?Sized, A: Allocator> FnMut<Args> for Box<F, A> {
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output {
}
}
+#[cfg(not(bootstrap))]
+#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
+impl<Args: Tuple, F: FnMut<Args> + ?Sized, A: Allocator> FnMut<Args> for Box<F, A> {
+ extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output {
+ <F as FnMut<Args>>::call_mut(self, args)
+ }
+}
+
+#[cfg(bootstrap)]
#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
impl<Args, F: Fn<Args> + ?Sized, A: Allocator> Fn<Args> for Box<F, A> {
extern "rust-call" fn call(&self, args: Args) -> Self::Output {
}
}
+#[cfg(not(bootstrap))]
+#[stable(feature = "boxed_closure_impls", since = "1.35.0")]
+impl<Args: Tuple, F: Fn<Args> + ?Sized, A: Allocator> Fn<Args> for Box<F, A> {
+ extern "rust-call" fn call(&self, args: Args) -> Self::Output {
+ <F as Fn<Args>>::call(self, args)
+ }
+}
+
#[unstable(feature = "coerce_unsized", issue = "27732")]
impl<T: ?Sized + Unsize<U>, U: ?Sized, A: Allocator> CoerceUnsized<Box<U, A>> for Box<T, A> {}
#[test]
#[cfg(target_arch = "x86_64")]
+#[cfg_attr(miri, ignore)] // We'd like to run Miri with layout randomization
fn test_sizes() {
assert_eq!(core::mem::size_of::<LeafNode<(), ()>>(), 16);
assert_eq!(core::mem::size_of::<LeafNode<i64, i64>>(), 16 + CAPACITY * 2 * 8);
" because the computed capacity exceeded the collection's maximum"
}
TryReserveErrorKind::AllocError { .. } => {
- " because the memory allocator returned a error"
+ " because the memory allocator returned an error"
}
};
fmt.write_str(reason)
use super::*;
#[bench]
-#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
fn bench_push_back_100(b: &mut test::Bencher) {
let mut deq = VecDeque::with_capacity(101);
b.iter(|| {
}
#[bench]
-#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
fn bench_push_front_100(b: &mut test::Bencher) {
let mut deq = VecDeque::with_capacity(101);
b.iter(|| {
}
#[bench]
-#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
fn bench_pop_back_100(b: &mut test::Bencher) {
- let mut deq = VecDeque::<i32>::with_capacity(101);
+ let size = 100;
+ let mut deq = VecDeque::<i32>::with_capacity(size + 1);
+ // We'll mess with private state to pretend like `deq` is filled.
+ // Make sure the buffer is initialized so that we don't read uninit memory.
+ unsafe { deq.ptr().write_bytes(0u8, size + 1) };
b.iter(|| {
- deq.head = 100;
+ deq.head = size;
deq.tail = 0;
while !deq.is_empty() {
test::black_box(deq.pop_back());
}
#[bench]
-#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
fn bench_retain_whole_10000(b: &mut test::Bencher) {
- let v = (1..100000).collect::<VecDeque<u32>>();
+ let size = if cfg!(miri) { 1000 } else { 100000 };
+ let v = (1..size).collect::<VecDeque<u32>>();
b.iter(|| {
let mut v = v.clone();
}
#[bench]
-#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
fn bench_retain_odd_10000(b: &mut test::Bencher) {
- let v = (1..100000).collect::<VecDeque<u32>>();
+ let size = if cfg!(miri) { 1000 } else { 100000 };
+ let v = (1..size).collect::<VecDeque<u32>>();
b.iter(|| {
let mut v = v.clone();
}
#[bench]
-#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
fn bench_retain_half_10000(b: &mut test::Bencher) {
- let v = (1..100000).collect::<VecDeque<u32>>();
+ let size = if cfg!(miri) { 1000 } else { 100000 };
+ let v = (1..size).collect::<VecDeque<u32>>();
b.iter(|| {
let mut v = v.clone();
- v.retain(|x| *x > 50000)
+ v.retain(|x| *x > size / 2)
})
}
#[bench]
-#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
fn bench_pop_front_100(b: &mut test::Bencher) {
- let mut deq = VecDeque::<i32>::with_capacity(101);
+ let size = 100;
+ let mut deq = VecDeque::<i32>::with_capacity(size + 1);
+ // We'll mess with private state to pretend like `deq` is filled.
+ // Make sure the buffer is initialized so that we don't read uninit memory.
+ unsafe { deq.ptr().write_bytes(0u8, size + 1) };
b.iter(|| {
- deq.head = 100;
+ deq.head = size;
deq.tail = 0;
while !deq.is_empty() {
test::black_box(deq.pop_front());
#![feature(trusted_len)]
#![feature(trusted_random_access)]
#![feature(try_trait_v2)]
+#![cfg_attr(not(bootstrap), feature(tuple_trait))]
#![feature(unchecked_math)]
#![feature(unicode_internals)]
#![feature(unsize)]
/// assert_eq!(string, "abcdecdeabecde");
/// ```
#[cfg(not(no_global_oom_handling))]
- #[unstable(feature = "string_extend_from_within", issue = "none")]
+ #[unstable(feature = "string_extend_from_within", issue = "103806")]
pub fn extend_from_within<R>(&mut self, src: R)
where
R: RangeBounds<usize>,
let (this, spare, len) = unsafe { self.split_at_spare_mut_with_len() };
// SAFETY:
- // - caller guaratees that src is a valid index
+ // - caller guarantees that src is a valid index
let to_clone = unsafe { this.get_unchecked(src) };
iter::zip(to_clone, spare)
let (init, spare) = self.split_at_spare_mut();
// SAFETY:
- // - caller guaratees that `src` is a valid index
+ // - caller guarantees that `src` is a valid index
let source = unsafe { init.get_unchecked(src) };
// SAFETY:
/// assert_eq!(v_iter.next(), None);
/// ```
#[inline]
- fn into_iter(self) -> IntoIter<T, A> {
+ fn into_iter(self) -> Self::IntoIter {
unsafe {
let mut me = ManuallyDrop::new(self);
let alloc = ManuallyDrop::new(ptr::read(me.allocator()));
type Item = &'a T;
type IntoIter = slice::Iter<'a, T>;
- fn into_iter(self) -> slice::Iter<'a, T> {
+ fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
type Item = &'a mut T;
type IntoIter = slice::IterMut<'a, T>;
- fn into_iter(self) -> slice::IterMut<'a, T> {
+ fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
+use core::borrow::Borrow;
use core::iter::*;
use core::mem;
use core::num::Wrapping;
/// Exercises the iter::Copied specialization for slice::Iter
#[bench]
-fn bench_copied_array_chunks(b: &mut Bencher) {
+fn bench_copied_chunks(b: &mut Bencher) {
+ let v = vec![1u8; 1024];
+
+ b.iter(|| {
+ let mut iter = black_box(&v).iter().copied();
+ let mut acc = Wrapping(0);
+ // This uses a while-let loop to side-step the TRA specialization in ArrayChunks
+ while let Ok(chunk) = iter.next_chunk::<{ mem::size_of::<u64>() }>() {
+ let d = u64::from_ne_bytes(chunk);
+ acc += Wrapping(d.rotate_left(7).wrapping_add(1));
+ }
+ acc
+ })
+}
+
+/// Exercises the TrustedRandomAccess specialization in ArrayChunks
+#[bench]
+fn bench_trusted_random_access_chunks(b: &mut Bencher) {
let v = vec![1u8; 1024];
b.iter(|| {
black_box(&v)
.iter()
- .copied()
+ // this shows that we're not relying on the slice::Iter specialization in Copied
+ .map(|b| *b.borrow())
.array_chunks::<{ mem::size_of::<u64>() }>()
.map(|ary| {
let d = u64::from_ne_bytes(ary);
// wasm32 does not support benches (no time).
#![cfg(not(target_arch = "wasm32"))]
#![feature(flt2dec)]
-#![feature(int_log)]
#![feature(test)]
#![feature(trusted_random_access)]
#![feature(iter_array_chunks)]
+#![feature(iter_next_chunk)]
extern crate test;
return Ok(Try::from_output(unsafe { mem::zeroed() }));
}
- struct Guard<'a, T, const N: usize> {
- array_mut: &'a mut [MaybeUninit<T>; N],
- initialized: usize,
- }
-
- impl<T, const N: usize> Drop for Guard<'_, T, N> {
- fn drop(&mut self) {
- debug_assert!(self.initialized <= N);
-
- // SAFETY: this slice will contain only initialized objects.
- unsafe {
- crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(
- &mut self.array_mut.get_unchecked_mut(..self.initialized),
- ));
- }
- }
- }
-
let mut array = MaybeUninit::uninit_array::<N>();
let mut guard = Guard { array_mut: &mut array, initialized: 0 };
ControlFlow::Continue(elem) => elem,
};
- // SAFETY: `guard.initialized` starts at 0, is increased by one in the
- // loop and the loop is aborted once it reaches N (which is
- // `array.len()`).
+ // SAFETY: `guard.initialized` starts at 0, which means push can be called
+ // at most N times, which this loop does.
unsafe {
- guard.array_mut.get_unchecked_mut(guard.initialized).write(item);
+ guard.push_unchecked(item);
}
- guard.initialized += 1;
}
None => {
let alive = 0..guard.initialized;
Ok(Try::from_output(output))
}
+/// Panic guard for incremental initialization of arrays.
+///
+/// Disarm the guard with `mem::forget` once the array has been initialized.
+///
+/// # Safety
+///
+/// All write accesses to this structure are unsafe and must maintain a correct
+/// count of `initialized` elements.
+///
+/// To minimize indirection fields are still pub but callers should at least use
+/// `push_unchecked` to signal that something unsafe is going on.
+pub(crate) struct Guard<'a, T, const N: usize> {
+ /// The array to be initialized.
+ pub array_mut: &'a mut [MaybeUninit<T>; N],
+ /// The number of items that have been initialized so far.
+ pub initialized: usize,
+}
+
+impl<T, const N: usize> Guard<'_, T, N> {
+ /// Adds an item to the array and updates the initialized item counter.
+ ///
+ /// # Safety
+ ///
+ /// No more than N elements must be initialized.
+ #[inline]
+ pub unsafe fn push_unchecked(&mut self, item: T) {
+ // SAFETY: If `initialized` was correct before and the caller does not
+ // invoke this method more than N times then writes will be in-bounds
+ // and slots will not be initialized more than once.
+ unsafe {
+ self.array_mut.get_unchecked_mut(self.initialized).write(item);
+ self.initialized = self.initialized.unchecked_add(1);
+ }
+ }
+}
+
+impl<T, const N: usize> Drop for Guard<'_, T, N> {
+ fn drop(&mut self) {
+ debug_assert!(self.initialized <= N);
+
+ // SAFETY: this slice will contain only initialized objects.
+ unsafe {
+ crate::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(
+ &mut self.array_mut.get_unchecked_mut(..self.initialized),
+ ));
+ }
+ }
+}
+
/// Returns the next chunk of `N` items from the iterator or errors with an
/// iterator over the remainder. Used for `Iterator::next_chunk`.
#[inline]
use crate::pin::Pin;
use crate::task::{Context, Poll};
-/// An interface for dealing with asynchronous iterators.
+/// A trait for dealing with asynchronous iterators.
///
/// This is the main async iterator trait. For more about the concept of async iterators
/// generally, please see the [module-level documentation]. In particular, you
///
/// [`.get_mut()`]: `UnsafeCell::get_mut`
///
+/// # Memory layout
+///
/// `UnsafeCell<T>` has the same in-memory representation as its inner type `T`. A consequence
/// of this guarantee is that it is possible to convert between `T` and `UnsafeCell<T>`.
/// Special care has to be taken when converting a nested `T` inside of an `Outer<T>` type
/// Therefore this is not a valid conversion, despite `NonNull<u8>` and `UnsafeCell<NonNull<u8>>>`
/// having the same memory layout. This is because `UnsafeCell` disables niche optimizations in
/// order to avoid its interior mutability property from spreading from `T` into the `Outer` type,
-/// thus this can cause distortions in the type size in these cases. Furthermore, it is only valid
-/// to obtain a `*mut T` pointer to the contents of a _shared_ `UnsafeCell<T>` through [`.get()`]
-/// or [`.raw_get()`]. A `&mut T` reference can be obtained by either dereferencing this pointer or
-/// by calling [`.get_mut()`] on an _exclusive_ `UnsafeCell<T>`, e.g.:
+/// thus this can cause distortions in the type size in these cases.
+///
+/// Note that the only valid way to obtain a `*mut T` pointer to the contents of a
+/// _shared_ `UnsafeCell<T>` is through [`.get()`] or [`.raw_get()`]. A `&mut T` reference
+/// can be obtained by either dereferencing this pointer or by calling [`.get_mut()`]
+/// on an _exclusive_ `UnsafeCell<T>`. Even though `T` and `UnsafeCell<T>` have the
+/// same memory layout, the following is not allowed and undefined behavior:
+///
+/// ```rust,no_run
+/// # use std::cell::UnsafeCell;
+/// unsafe fn not_allowed<T>(ptr: &UnsafeCell<T>) -> &mut T {
+/// let t = ptr as *const UnsafeCell<T> as *mut T;
+/// // This is undefined behavior, because the `*mut T` pointer
+/// // was not obtained through `.get()` nor `.raw_get()`:
+/// unsafe { &mut *t }
+/// }
+/// ```
+///
+/// Instead, do this:
///
/// ```rust
-/// use std::cell::UnsafeCell;
+/// # use std::cell::UnsafeCell;
+/// // Safety: the caller must ensure that there are no references that
+/// // point to the *contents* of the `UnsafeCell`.
+/// unsafe fn get_mut<T>(ptr: &UnsafeCell<T>) -> &mut T {
+/// unsafe { &mut *ptr.get() }
+/// }
+/// ```
///
-/// let mut x: UnsafeCell<u32> = UnsafeCell::new(5);
-/// let shared: &UnsafeCell<u32> = &x;
-/// // using `.get()` is okay:
-/// unsafe {
-/// // SAFETY: there exist no other references to the contents of `x`
-/// let exclusive: &mut u32 = &mut *shared.get();
-/// };
-/// // using `.raw_get()` is also okay:
-/// unsafe {
-/// // SAFETY: there exist no other references to the contents of `x` in this scope
-/// let exclusive: &mut u32 = &mut *UnsafeCell::raw_get(shared as *const _);
-/// };
-/// // using `.get_mut()` is always safe:
-/// let exclusive: &mut u32 = x.get_mut();
+/// Converting in the other direction from a `&mut T`
+/// to an `&UnsafeCell<T>` is allowed:
///
-/// // when we have exclusive access, we can convert it to a shared `&UnsafeCell`:
-/// unsafe {
-/// // SAFETY: `u32` has no niche, therefore it has the same layout as `UnsafeCell<u32>`
-/// let shared: &UnsafeCell<u32> = &*(exclusive as *mut _ as *const UnsafeCell<u32>);
-/// // SAFETY: there exist no other *active* references to the contents of `x` in this scope
-/// let exclusive: &mut u32 = &mut *shared.get();
+/// ```rust
+/// # use std::cell::UnsafeCell;
+/// fn get_shared<T>(ptr: &mut T) -> &UnsafeCell<T> {
+/// let t = ptr as *mut T as *const UnsafeCell<T>;
+/// // SAFETY: `T` and `UnsafeCell<T>` have the same memory layout
+/// unsafe { &*t }
/// }
/// ```
///
/// Constructs a new instance of `UnsafeCell` which will wrap the specified
/// value.
///
- /// All access to the inner value through methods is `unsafe`.
+ /// All access to the inner value through `&UnsafeCell<T>` requires `unsafe` code.
///
/// # Examples
///
use crate::marker::Destruct;
+#[cfg(not(bootstrap))]
+use crate::marker::Tuple;
/// Struct representing a closure with mutably borrowed data.
///
macro_rules! impl_fn_mut_tuple {
($($var:ident)*) => {
+ #[cfg(bootstrap)]
#[allow(unused_parens)]
impl<'a, $($var,)* ClosureArguments, Function, ClosureReturnValue> const
FnOnce<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
self.call_mut(args)
}
}
+ #[cfg(bootstrap)]
#[allow(unused_parens)]
impl<'a, $($var,)* ClosureArguments, Function, ClosureReturnValue> const
FnMut<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
(self.func)(($($var),*), args)
}
}
+ #[cfg(not(bootstrap))]
+ #[allow(unused_parens)]
+ impl<'a, $($var,)* ClosureArguments: Tuple, Function, ClosureReturnValue> const
+ FnOnce<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
+ where
+ Function: ~const Fn(($(&mut $var),*), ClosureArguments) -> ClosureReturnValue+ ~const Destruct,
+ {
+ type Output = ClosureReturnValue;
+
+ extern "rust-call" fn call_once(mut self, args: ClosureArguments) -> Self::Output {
+ self.call_mut(args)
+ }
+ }
+ #[cfg(not(bootstrap))]
+ #[allow(unused_parens)]
+ impl<'a, $($var,)* ClosureArguments: Tuple, Function, ClosureReturnValue> const
+ FnMut<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
+ where
+ Function: ~const Fn(($(&mut $var),*), ClosureArguments)-> ClosureReturnValue,
+ {
+ extern "rust-call" fn call_mut(&mut self, args: ClosureArguments) -> Self::Output {
+ #[allow(non_snake_case)]
+ let ($($var),*) = &mut self.data;
+ (self.func)(($($var),*), args)
+ }
+ }
};
}
impl_fn_mut_tuple!(A);
`Result` is `Ok` or panic if the `Result` is `Err` printing the inner error
as the source. The only difference between them is that with `expect` you
provide a panic error message to be printed alongside the source, whereas
-`unwrap` has a default message indicating only that you unwraped an `Err`.
+`unwrap` has a default message indicating only that you unwrapped an `Err`.
Of the two, `expect` is generally preferred since its `msg` field allows you
to convey your intent and assumptions which makes tracking down the source
#![doc = include_str!("error.md")]
-#![unstable(feature = "error_in_core", issue = "none")]
+#![unstable(feature = "error_in_core", issue = "103765")]
#[cfg(test)]
mod tests;
/// array of bytes. It can be constructed safely from a <code>&[[u8]]</code>
/// slice, or unsafely from a raw `*const c_char`. It can then be
/// converted to a Rust <code>&[str]</code> by performing UTF-8 validation, or
-/// into an owned `CString`.
+/// into an owned [`CString`].
///
-/// `&CStr` is to `CString` as <code>&[str]</code> is to `String`: the former
+/// `&CStr` is to [`CString`] as <code>&[str]</code> is to [`String`]: the former
/// in each pair are borrowed references; the latter are owned
/// strings.
///
/// functions may leverage the unsafe [`CStr::from_ptr`] constructor to provide
/// a safe interface to other consumers.
///
+/// [`CString`]: ../../std/ffi/struct.CString.html
+/// [`String`]: ../../std/string/struct.String.html
+///
/// # Examples
///
/// Inspecting a foreign C string:
/// # Examples
///
/// ```ignore (extern-declaration)
- /// # fn main() {
- /// use std::ffi::CStr;
- /// use std::os::raw::c_char;
+ /// use std::ffi::{c_char, CStr};
///
/// extern "C" {
/// fn my_string() -> *const c_char;
/// let slice = CStr::from_ptr(my_string());
/// println!("string returned: {}", slice.to_str().unwrap());
/// }
- /// # }
+ /// ```
+ ///
+ /// ```
+ /// #![feature(const_cstr_methods)]
+ ///
+ /// use std::ffi::{c_char, CStr};
+ ///
+ /// const HELLO_PTR: *const c_char = {
+ /// const BYTES: &[u8] = b"Hello, world!\0";
+ /// BYTES.as_ptr().cast()
+ /// };
+ /// const HELLO: &CStr = unsafe { CStr::from_ptr(HELLO_PTR) };
/// ```
///
/// [valid]: core::ptr#safety
#[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
- pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
+ #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")]
+ pub const unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
// SAFETY: The caller has provided a pointer that points to a valid C
// string with a NUL terminator of size less than `isize::MAX`, whose
// content remain valid and doesn't change for the lifetime of the
//
// The cast from c_char to u8 is ok because a c_char is always one byte.
unsafe {
- extern "C" {
- /// Provided by libc or compiler_builtins.
- fn strlen(s: *const c_char) -> usize;
+ const fn strlen_ct(s: *const c_char) -> usize {
+ let mut len = 0;
+
+ // SAFETY: Outer caller has provided a pointer to a valid C string.
+ while unsafe { *s.add(len) } != 0 {
+ len += 1;
+ }
+
+ len
}
- let len = strlen(ptr);
- let ptr = ptr as *const u8;
- CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1))
+
+ fn strlen_rt(s: *const c_char) -> usize {
+ extern "C" {
+ /// Provided by libc or compiler_builtins.
+ fn strlen(s: *const c_char) -> usize;
+ }
+
+ // SAFETY: Outer caller has provided a pointer to a valid C string.
+ unsafe { strlen(s) }
+ }
+
+ let len = intrinsics::const_eval_select((ptr,), strlen_ct, strlen_rt);
+ Self::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr.cast(), len + 1))
}
}
/// Creates a future that wraps a function returning [`Poll`].
///
-/// Polling the future delegates to the wrapped function.
+/// Polling the future delegates to the wrapped function. If the returned future is pinned, then the
+/// captured environment of the wrapped function is also pinned in-place, so as long as the closure
+/// does not move out of its captures it can soundly create pinned references to them.
///
/// # Examples
///
}
#[stable(feature = "future_poll_fn", since = "1.64.0")]
-impl<F> Unpin for PollFn<F> {}
+impl<F: Unpin> Unpin for PollFn<F> {}
#[stable(feature = "future_poll_fn", since = "1.64.0")]
impl<F> fmt::Debug for PollFn<F> {
{
type Output = T;
- fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> {
- (&mut self.f)(cx)
+ fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<T> {
+ // SAFETY: We are not moving out of the pinned field.
+ (unsafe { &mut self.get_unchecked_mut().f })(cx)
}
}
// SAFETY: the safety contract for `intrinsics::unreachable` must
// be upheld by the caller.
unsafe {
- intrinsics::assert_unsafe_precondition!(() => false);
+ intrinsics::assert_unsafe_precondition!("hint::unreachable_unchecked must never be reached", () => false);
intrinsics::unreachable()
}
}
#![allow(missing_docs)]
use crate::marker::DiscriminantKind;
+#[cfg(not(bootstrap))]
+use crate::marker::Tuple;
use crate::mem;
// These imports are used for simplifying intra-doc links
/// `unreachable_unchecked` is actually being reached. The bug is in *crate A*,
/// which violates the principle that a `const fn` must behave the same at
/// compile-time and at run-time. The unsafe code in crate B is fine.
+ #[cfg(bootstrap)]
#[rustc_const_unstable(feature = "const_eval_select", issue = "none")]
pub fn const_eval_select<ARG, F, G, RET>(arg: ARG, called_in_const: F, called_at_rt: G) -> RET
where
G: FnOnce<ARG, Output = RET>,
F: FnOnce<ARG, Output = RET>;
+
+ /// Selects which function to call depending on the context.
+ ///
+ /// If this function is evaluated at compile-time, then a call to this
+ /// intrinsic will be replaced with a call to `called_in_const`. It gets
+ /// replaced with a call to `called_at_rt` otherwise.
+ ///
+ /// # Type Requirements
+ ///
+ /// The two functions must be both function items. They cannot be function
+ /// pointers or closures. The first function must be a `const fn`.
+ ///
+ /// `arg` will be the tupled arguments that will be passed to either one of
+ /// the two functions, therefore, both functions must accept the same type of
+ /// arguments. Both functions must return RET.
+ ///
+ /// # Safety
+ ///
+ /// The two functions must behave observably equivalent. Safe code in other
+ /// crates may assume that calling a `const fn` at compile-time and at run-time
+ /// produces the same result. A function that produces a different result when
+ /// evaluated at run-time, or has any other observable side-effects, is
+ /// *unsound*.
+ ///
+ /// Here is an example of how this could cause a problem:
+ /// ```no_run
+ /// #![feature(const_eval_select)]
+ /// #![feature(core_intrinsics)]
+ /// use std::hint::unreachable_unchecked;
+ /// use std::intrinsics::const_eval_select;
+ ///
+ /// // Crate A
+ /// pub const fn inconsistent() -> i32 {
+ /// fn runtime() -> i32 { 1 }
+ /// const fn compiletime() -> i32 { 2 }
+ ///
+ /// unsafe {
+ // // ⚠ This code violates the required equivalence of `compiletime`
+ /// // and `runtime`.
+ /// const_eval_select((), compiletime, runtime)
+ /// }
+ /// }
+ ///
+ /// // Crate B
+ /// const X: i32 = inconsistent();
+ /// let x = inconsistent();
+ /// if x != X { unsafe { unreachable_unchecked(); }}
+ /// ```
+ ///
+ /// This code causes Undefined Behavior when being run, since the
+ /// `unreachable_unchecked` is actually being reached. The bug is in *crate A*,
+ /// which violates the principle that a `const fn` must behave the same at
+ /// compile-time and at run-time. The unsafe code in crate B is fine.
+ #[cfg(not(bootstrap))]
+ #[rustc_const_unstable(feature = "const_eval_select", issue = "none")]
+ pub fn const_eval_select<ARG: Tuple, F, G, RET>(
+ arg: ARG,
+ called_in_const: F,
+ called_at_rt: G,
+ ) -> RET
+ where
+ G: FnOnce<ARG, Output = RET>,
+ F: FnOnce<ARG, Output = RET>;
}
// Some functions are defined here because they accidentally got made
/// the occasional mistake, and this check should help them figure things out.
#[allow_internal_unstable(const_eval_select)] // permit this to be called in stably-const fn
macro_rules! assert_unsafe_precondition {
- ($([$($tt:tt)*])?($($i:ident:$ty:ty),*$(,)?) => $e:expr) => {
+ ($name:expr, $([$($tt:tt)*])?($($i:ident:$ty:ty),*$(,)?) => $e:expr) => {
if cfg!(debug_assertions) {
// allow non_snake_case to allow capturing const generics
#[allow(non_snake_case)]
fn runtime$(<$($tt)*>)?($($i:$ty),*) {
if !$e {
// don't unwind to reduce impact on code size
- ::core::panicking::panic_str_nounwind("unsafe precondition violated");
+ ::core::panicking::panic_str_nounwind(
+ concat!("unsafe precondition(s) violated: ", $name)
+ );
}
}
#[allow(non_snake_case)]
// SAFETY: the safety contract for `copy_nonoverlapping` must be
// upheld by the caller.
unsafe {
- assert_unsafe_precondition!([T](src: *const T, dst: *mut T, count: usize) =>
+ assert_unsafe_precondition!(
+ "ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null \
+ and the specified memory ranges do not overlap",
+ [T](src: *const T, dst: *mut T, count: usize) =>
is_aligned_and_not_null(src)
&& is_aligned_and_not_null(dst)
&& is_nonoverlapping(src, dst, count)
// SAFETY: the safety contract for `copy` must be upheld by the caller.
unsafe {
- assert_unsafe_precondition!([T](src: *const T, dst: *mut T) =>
- is_aligned_and_not_null(src) && is_aligned_and_not_null(dst));
+ assert_unsafe_precondition!(
+ "ptr::copy requires that both pointer arguments are aligned aligned and non-null",
+ [T](src: *const T, dst: *mut T) =>
+ is_aligned_and_not_null(src) && is_aligned_and_not_null(dst)
+ );
copy(src, dst, count)
}
}
// SAFETY: the safety contract for `write_bytes` must be upheld by the caller.
unsafe {
- assert_unsafe_precondition!([T](dst: *mut T) => is_aligned_and_not_null(dst));
+ assert_unsafe_precondition!(
+ "ptr::write_bytes requires that the destination pointer is aligned and non-null",
+ [T](dst: *mut T) => is_aligned_and_not_null(dst)
+ );
write_bytes(dst, val, count)
}
}
use crate::array;
-use crate::iter::{ByRefSized, FusedIterator, Iterator};
-use crate::ops::{ControlFlow, Try};
+use crate::const_closure::ConstFnMutClosure;
+use crate::iter::{ByRefSized, FusedIterator, Iterator, TrustedRandomAccessNoCoerce};
+use crate::mem::{self, MaybeUninit};
+use crate::ops::{ControlFlow, NeverShortCircuit, Try};
/// An iterator over `N` elements of the iterator at a time.
///
}
}
- impl_fold_via_try_fold! { fold -> try_fold }
+ fn fold<B, F>(self, init: B, f: F) -> B
+ where
+ Self: Sized,
+ F: FnMut(B, Self::Item) -> B,
+ {
+ <Self as SpecFold>::fold(self, init, f)
+ }
}
#[unstable(feature = "iter_array_chunks", reason = "recently added", issue = "100450")]
self.iter.len() < N
}
}
+
+trait SpecFold: Iterator {
+ fn fold<B, F>(self, init: B, f: F) -> B
+ where
+ Self: Sized,
+ F: FnMut(B, Self::Item) -> B;
+}
+
+impl<I, const N: usize> SpecFold for ArrayChunks<I, N>
+where
+ I: Iterator,
+{
+ #[inline]
+ default fn fold<B, F>(mut self, init: B, mut f: F) -> B
+ where
+ Self: Sized,
+ F: FnMut(B, Self::Item) -> B,
+ {
+ let fold = ConstFnMutClosure::new(&mut f, NeverShortCircuit::wrap_mut_2_imp);
+ self.try_fold(init, fold).0
+ }
+}
+
+impl<I, const N: usize> SpecFold for ArrayChunks<I, N>
+where
+ I: Iterator + TrustedRandomAccessNoCoerce,
+{
+ #[inline]
+ fn fold<B, F>(mut self, init: B, mut f: F) -> B
+ where
+ Self: Sized,
+ F: FnMut(B, Self::Item) -> B,
+ {
+ let mut accum = init;
+ let inner_len = self.iter.size();
+ let mut i = 0;
+ // Use a while loop because (0..len).step_by(N) doesn't optimize well.
+ while inner_len - i >= N {
+ let mut chunk = MaybeUninit::uninit_array();
+ let mut guard = array::Guard { array_mut: &mut chunk, initialized: 0 };
+ while guard.initialized < N {
+ // SAFETY: The method consumes the iterator and the loop condition ensures that
+ // all accesses are in bounds and only happen once.
+ unsafe {
+ let idx = i + guard.initialized;
+ guard.push_unchecked(self.iter.__iterator_get_unchecked(idx));
+ }
+ }
+ mem::forget(guard);
+ // SAFETY: The loop above initialized all elements
+ let chunk = unsafe { MaybeUninit::array_assume_init(chunk) };
+ accum = f(accum, chunk);
+ i += N;
+ }
+
+ // unlike try_fold this method does not need to take care of the remainder
+ // since `self` will be dropped
+
+ accum
+ }
+}
fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
-/// An interface for dealing with iterators.
+/// A trait for dealing with iterators.
///
/// This is the main iterator trait. For more about the concept of iterators
/// generally, please see the [module-level documentation]. In particular, you
/* compiler built-in */
}
+ /// Attribute macro applied to a function to register it as a handler for allocation failure.
+ ///
+ /// See also [`std::alloc::handle_alloc_error`](../../../std/alloc/fn.handle_alloc_error.html).
+ #[cfg(not(bootstrap))]
+ #[unstable(feature = "alloc_error_handler", issue = "51540")]
+ #[allow_internal_unstable(rustc_attrs)]
+ #[rustc_builtin_macro]
+ pub macro alloc_error_handler($item:item) {
+ /* compiler built-in */
+ }
+
/// Keeps the item it's applied to if the passed path is accessible, and removes it otherwise.
#[unstable(
feature = "cfg_accessible",
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> !Send for *mut T {}
+// Most instances arise automatically, but this instance is needed to link up `T: Sync` with
+// `&T: Send` (and it also removes the unsound default instance `T Send` -> `&T: Send` that would
+// otherwise exist).
+#[stable(feature = "rust1", since = "1.0.0")]
+unsafe impl<T: Sync + ?Sized> Send for &T {}
+
/// Types with a constant size known at compile time.
///
/// All type parameters have an implicit bound of `Sized`. The special syntax
#[unstable(feature = "structural_match", issue = "31434")]
impl<T: ?Sized> StructuralEq for PhantomData<T> {}
-mod impls {
- #[stable(feature = "rust1", since = "1.0.0")]
- unsafe impl<T: Sync + ?Sized> Send for &T {}
- #[stable(feature = "rust1", since = "1.0.0")]
- unsafe impl<T: Send + ?Sized> Send for &mut T {}
-}
-
/// Compiler-internal trait used to indicate the type of enum discriminants.
///
/// This trait is automatically implemented for every type and does not add any
/// ```
#[inline]
#[unstable(feature = "mem_copy_fn", issue = "98262")]
-pub fn copy<T: Copy>(x: &T) -> T {
+pub const fn copy<T: Copy>(x: &T) -> T {
*x
}
/// # Panics
///
/// This function will panic if `self` is less than or equal to zero,
- /// or if `base` is less then 2.
+ /// or if `base` is less than 2.
///
/// # Examples
///
/// ```
- /// #![feature(int_log)]
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".ilog(5), 1);")]
/// ```
- #[unstable(feature = "int_log", issue = "70887")]
+ #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_allow_const_fn_unstable(const_option)]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
/// # Examples
///
/// ```
- /// #![feature(int_log)]
#[doc = concat!("assert_eq!(2", stringify!($SelfT), ".ilog2(), 1);")]
/// ```
- #[unstable(feature = "int_log", issue = "70887")]
+ #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_allow_const_fn_unstable(const_option)]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
/// # Example
///
/// ```
- /// #![feature(int_log)]
#[doc = concat!("assert_eq!(10", stringify!($SelfT), ".ilog10(), 1);")]
/// ```
- #[unstable(feature = "int_log", issue = "70887")]
+ #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_allow_const_fn_unstable(const_option)]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
/// # Examples
///
/// ```
- /// #![feature(int_log)]
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_ilog(5), Some(1));")]
/// ```
- #[unstable(feature = "int_log", issue = "70887")]
+ #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
/// # Examples
///
/// ```
- /// #![feature(int_log)]
#[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_ilog2(), Some(1));")]
/// ```
- #[unstable(feature = "int_log", issue = "70887")]
+ #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
/// # Example
///
/// ```
- /// #![feature(int_log)]
#[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_ilog10(), Some(1));")]
/// ```
- #[unstable(feature = "int_log", issue = "70887")]
+ #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
pub const unsafe fn new_unchecked(n: $Int) -> Self {
// SAFETY: this is guaranteed to be safe by the caller.
unsafe {
- core::intrinsics::assert_unsafe_precondition!((n: $Int) => n != 0);
+ core::intrinsics::assert_unsafe_precondition!(
+ concat!(stringify!($Ty), "::new_unchecked requires a non-zero argument"),
+ (n: $Int) => n != 0
+ );
Self(n)
}
}
/// # Examples
///
/// ```
- /// #![feature(int_log)]
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
#[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().ilog2(), 2);")]
#[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().ilog2(), 3);")]
#[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().ilog2(), 3);")]
/// ```
- #[unstable(feature = "int_log", issue = "70887")]
+ #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
/// # Examples
///
/// ```
- /// #![feature(int_log)]
#[doc = concat!("# use std::num::", stringify!($Ty), ";")]
///
#[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().ilog10(), 1);")]
#[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().ilog10(), 2);")]
#[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().ilog10(), 2);")]
/// ```
- #[unstable(feature = "int_log", issue = "70887")]
+ #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
///
/// # Panics
///
- /// This function will panic if `self` is zero, or if `base` is less then 2.
+ /// This function will panic if `self` is zero, or if `base` is less than 2.
///
/// # Examples
///
/// ```
- /// #![feature(int_log)]
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".ilog(5), 1);")]
/// ```
- #[unstable(feature = "int_log", issue = "70887")]
+ #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_allow_const_fn_unstable(const_option)]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
/// # Examples
///
/// ```
- /// #![feature(int_log)]
#[doc = concat!("assert_eq!(2", stringify!($SelfT), ".ilog2(), 1);")]
/// ```
- #[unstable(feature = "int_log", issue = "70887")]
+ #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_allow_const_fn_unstable(const_option)]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
/// # Example
///
/// ```
- /// #![feature(int_log)]
#[doc = concat!("assert_eq!(10", stringify!($SelfT), ".ilog10(), 1);")]
/// ```
- #[unstable(feature = "int_log", issue = "70887")]
+ #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_allow_const_fn_unstable(const_option)]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
/// # Examples
///
/// ```
- /// #![feature(int_log)]
#[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_ilog(5), Some(1));")]
/// ```
- #[unstable(feature = "int_log", issue = "70887")]
+ #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
/// # Examples
///
/// ```
- /// #![feature(int_log)]
#[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_ilog2(), Some(1));")]
/// ```
- #[unstable(feature = "int_log", issue = "70887")]
+ #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
/// # Examples
///
/// ```
- /// #![feature(int_log)]
#[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_ilog10(), Some(1));")]
/// ```
- #[unstable(feature = "int_log", issue = "70887")]
+ #[stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
+ #[rustc_const_stable(feature = "int_log", since = "CURRENT_RUSTC_VERSION")]
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[inline]
/// [`Break`]: ControlFlow::Break
/// [`Continue`]: ControlFlow::Continue
#[stable(feature = "control_flow_enum_type", since = "1.55.0")]
-#[derive(Debug, Clone, Copy, PartialEq)]
+// ControlFlow should not implement PartialOrd or Ord, per RFC 3058:
+// https://rust-lang.github.io/rfcs/3058-try-trait-v2.html#traits-for-controlflow
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ControlFlow<B, C = ()> {
/// Move on to the next phase of the operation as normal.
#[stable(feature = "control_flow_enum_type", since = "1.55.0")]
+#[cfg(not(bootstrap))]
+use crate::marker::Tuple;
+
/// The version of the call operator that takes an immutable receiver.
///
/// Instances of `Fn` can be called repeatedly without mutating state.
/// let double = |x| x * 2;
/// assert_eq!(call_with_one(double), 2);
/// ```
+#[cfg(bootstrap)]
#[lang = "fn"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "Fn"]
)]
#[fundamental] // so that regex can rely that `&str: !FnMut`
#[must_use = "closures are lazy and do nothing unless called"]
-#[cfg_attr(not(bootstrap), const_trait)]
pub trait Fn<Args>: FnMut<Args> {
/// Performs the call operation.
#[unstable(feature = "fn_traits", issue = "29625")]
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
}
+/// The version of the call operator that takes an immutable receiver.
+///
+/// Instances of `Fn` can be called repeatedly without mutating state.
+///
+/// *This trait (`Fn`) is not to be confused with [function pointers]
+/// (`fn`).*
+///
+/// `Fn` is implemented automatically by closures which only take immutable
+/// references to captured variables or don't capture anything at all, as well
+/// as (safe) [function pointers] (with some caveats, see their documentation
+/// for more details). Additionally, for any type `F` that implements `Fn`, `&F`
+/// implements `Fn`, too.
+///
+/// Since both [`FnMut`] and [`FnOnce`] are supertraits of `Fn`, any
+/// instance of `Fn` can be used as a parameter where a [`FnMut`] or [`FnOnce`]
+/// is expected.
+///
+/// Use `Fn` as a bound when you want to accept a parameter of function-like
+/// type and need to call it repeatedly and without mutating state (e.g., when
+/// calling it concurrently). If you do not need such strict requirements, use
+/// [`FnMut`] or [`FnOnce`] as bounds.
+///
+/// See the [chapter on closures in *The Rust Programming Language*][book] for
+/// some more information on this topic.
+///
+/// Also of note is the special syntax for `Fn` traits (e.g.
+/// `Fn(usize, bool) -> usize`). Those interested in the technical details of
+/// this can refer to [the relevant section in the *Rustonomicon*][nomicon].
+///
+/// [book]: ../../book/ch13-01-closures.html
+/// [function pointers]: fn
+/// [nomicon]: ../../nomicon/hrtb.html
+///
+/// # Examples
+///
+/// ## Calling a closure
+///
+/// ```
+/// let square = |x| x * x;
+/// assert_eq!(square(5), 25);
+/// ```
+///
+/// ## Using a `Fn` parameter
+///
+/// ```
+/// fn call_with_one<F>(func: F) -> usize
+/// where F: Fn(usize) -> usize {
+/// func(1)
+/// }
+///
+/// let double = |x| x * 2;
+/// assert_eq!(call_with_one(double), 2);
+/// ```
+#[cfg(not(bootstrap))]
+#[lang = "fn"]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_diagnostic_item = "Fn"]
+#[rustc_paren_sugar]
+#[rustc_on_unimplemented(
+ on(
+ Args = "()",
+ note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
+ ),
+ on(
+ _Self = "unsafe fn",
+ note = "unsafe function cannot be called generically without an unsafe block",
+ // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string
+ label = "call the function in a closure: `|| unsafe {{ /* code */ }}`"
+ ),
+ message = "expected a `{Fn}<{Args}>` closure, found `{Self}`",
+ label = "expected an `Fn<{Args}>` closure, found `{Self}`"
+)]
+#[fundamental] // so that regex can rely that `&str: !FnMut`
+#[must_use = "closures are lazy and do nothing unless called"]
+#[const_trait]
+pub trait Fn<Args: Tuple>: FnMut<Args> {
+ /// Performs the call operation.
+ #[unstable(feature = "fn_traits", issue = "29625")]
+ extern "rust-call" fn call(&self, args: Args) -> Self::Output;
+}
+
/// The version of the call operator that takes a mutable receiver.
///
/// Instances of `FnMut` can be called repeatedly and may mutate state.
///
/// assert_eq!(x, 5);
/// ```
+#[cfg(bootstrap)]
#[lang = "fn_mut"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "FnMut"]
)]
#[fundamental] // so that regex can rely that `&str: !FnMut`
#[must_use = "closures are lazy and do nothing unless called"]
-#[cfg_attr(not(bootstrap), const_trait)]
pub trait FnMut<Args>: FnOnce<Args> {
/// Performs the call operation.
#[unstable(feature = "fn_traits", issue = "29625")]
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}
+/// The version of the call operator that takes a mutable receiver.
+///
+/// Instances of `FnMut` can be called repeatedly and may mutate state.
+///
+/// `FnMut` is implemented automatically by closures which take mutable
+/// references to captured variables, as well as all types that implement
+/// [`Fn`], e.g., (safe) [function pointers] (since `FnMut` is a supertrait of
+/// [`Fn`]). Additionally, for any type `F` that implements `FnMut`, `&mut F`
+/// implements `FnMut`, too.
+///
+/// Since [`FnOnce`] is a supertrait of `FnMut`, any instance of `FnMut` can be
+/// used where a [`FnOnce`] is expected, and since [`Fn`] is a subtrait of
+/// `FnMut`, any instance of [`Fn`] can be used where `FnMut` is expected.
+///
+/// Use `FnMut` as a bound when you want to accept a parameter of function-like
+/// type and need to call it repeatedly, while allowing it to mutate state.
+/// If you don't want the parameter to mutate state, use [`Fn`] as a
+/// bound; if you don't need to call it repeatedly, use [`FnOnce`].
+///
+/// See the [chapter on closures in *The Rust Programming Language*][book] for
+/// some more information on this topic.
+///
+/// Also of note is the special syntax for `Fn` traits (e.g.
+/// `Fn(usize, bool) -> usize`). Those interested in the technical details of
+/// this can refer to [the relevant section in the *Rustonomicon*][nomicon].
+///
+/// [book]: ../../book/ch13-01-closures.html
+/// [function pointers]: fn
+/// [nomicon]: ../../nomicon/hrtb.html
+///
+/// # Examples
+///
+/// ## Calling a mutably capturing closure
+///
+/// ```
+/// let mut x = 5;
+/// {
+/// let mut square_x = || x *= x;
+/// square_x();
+/// }
+/// assert_eq!(x, 25);
+/// ```
+///
+/// ## Using a `FnMut` parameter
+///
+/// ```
+/// fn do_twice<F>(mut func: F)
+/// where F: FnMut()
+/// {
+/// func();
+/// func();
+/// }
+///
+/// let mut x: usize = 1;
+/// {
+/// let add_two_to_x = || x += 2;
+/// do_twice(add_two_to_x);
+/// }
+///
+/// assert_eq!(x, 5);
+/// ```
+#[cfg(not(bootstrap))]
+#[lang = "fn_mut"]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_diagnostic_item = "FnMut"]
+#[rustc_paren_sugar]
+#[rustc_on_unimplemented(
+ on(
+ Args = "()",
+ note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
+ ),
+ on(
+ _Self = "unsafe fn",
+ note = "unsafe function cannot be called generically without an unsafe block",
+ // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string
+ label = "call the function in a closure: `|| unsafe {{ /* code */ }}`"
+ ),
+ message = "expected a `{FnMut}<{Args}>` closure, found `{Self}`",
+ label = "expected an `FnMut<{Args}>` closure, found `{Self}`"
+)]
+#[fundamental] // so that regex can rely that `&str: !FnMut`
+#[must_use = "closures are lazy and do nothing unless called"]
+#[const_trait]
+pub trait FnMut<Args: Tuple>: FnOnce<Args> {
+ /// Performs the call operation.
+ #[unstable(feature = "fn_traits", issue = "29625")]
+ extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
+}
+
/// The version of the call operator that takes a by-value receiver.
///
/// Instances of `FnOnce` can be called, but might not be callable multiple
///
/// // `consume_and_return_x` can no longer be invoked at this point
/// ```
+#[cfg(bootstrap)]
#[lang = "fn_once"]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_diagnostic_item = "FnOnce"]
)]
#[fundamental] // so that regex can rely that `&str: !FnMut`
#[must_use = "closures are lazy and do nothing unless called"]
-#[cfg_attr(not(bootstrap), const_trait)]
pub trait FnOnce<Args> {
/// The returned type after the call operator is used.
#[lang = "fn_once_output"]
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}
+/// The version of the call operator that takes a by-value receiver.
+///
+/// Instances of `FnOnce` can be called, but might not be callable multiple
+/// times. Because of this, if the only thing known about a type is that it
+/// implements `FnOnce`, it can only be called once.
+///
+/// `FnOnce` is implemented automatically by closures that might consume captured
+/// variables, as well as all types that implement [`FnMut`], e.g., (safe)
+/// [function pointers] (since `FnOnce` is a supertrait of [`FnMut`]).
+///
+/// Since both [`Fn`] and [`FnMut`] are subtraits of `FnOnce`, any instance of
+/// [`Fn`] or [`FnMut`] can be used where a `FnOnce` is expected.
+///
+/// Use `FnOnce` as a bound when you want to accept a parameter of function-like
+/// type and only need to call it once. If you need to call the parameter
+/// repeatedly, use [`FnMut`] as a bound; if you also need it to not mutate
+/// state, use [`Fn`].
+///
+/// See the [chapter on closures in *The Rust Programming Language*][book] for
+/// some more information on this topic.
+///
+/// Also of note is the special syntax for `Fn` traits (e.g.
+/// `Fn(usize, bool) -> usize`). Those interested in the technical details of
+/// this can refer to [the relevant section in the *Rustonomicon*][nomicon].
+///
+/// [book]: ../../book/ch13-01-closures.html
+/// [function pointers]: fn
+/// [nomicon]: ../../nomicon/hrtb.html
+///
+/// # Examples
+///
+/// ## Using a `FnOnce` parameter
+///
+/// ```
+/// fn consume_with_relish<F>(func: F)
+/// where F: FnOnce() -> String
+/// {
+/// // `func` consumes its captured variables, so it cannot be run more
+/// // than once.
+/// println!("Consumed: {}", func());
+///
+/// println!("Delicious!");
+///
+/// // Attempting to invoke `func()` again will throw a `use of moved
+/// // value` error for `func`.
+/// }
+///
+/// let x = String::from("x");
+/// let consume_and_return_x = move || x;
+/// consume_with_relish(consume_and_return_x);
+///
+/// // `consume_and_return_x` can no longer be invoked at this point
+/// ```
+#[cfg(not(bootstrap))]
+#[lang = "fn_once"]
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_diagnostic_item = "FnOnce"]
+#[rustc_paren_sugar]
+#[rustc_on_unimplemented(
+ on(
+ Args = "()",
+ note = "wrap the `{Self}` in a closure with no arguments: `|| {{ /* code */ }}`"
+ ),
+ on(
+ _Self = "unsafe fn",
+ note = "unsafe function cannot be called generically without an unsafe block",
+ // SAFETY: tidy is not smart enough to tell that the below unsafe block is a string
+ label = "call the function in a closure: `|| unsafe {{ /* code */ }}`"
+ ),
+ message = "expected a `{FnOnce}<{Args}>` closure, found `{Self}`",
+ label = "expected an `FnOnce<{Args}>` closure, found `{Self}`"
+)]
+#[fundamental] // so that regex can rely that `&str: !FnMut`
+#[must_use = "closures are lazy and do nothing unless called"]
+#[const_trait]
+pub trait FnOnce<Args: Tuple> {
+ /// The returned type after the call operator is used.
+ #[lang = "fn_once_output"]
+ #[stable(feature = "fn_once_output", since = "1.12.0")]
+ type Output;
+
+ /// Performs the call operation.
+ #[unstable(feature = "fn_traits", issue = "29625")]
+ extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+}
+
+#[cfg(bootstrap)]
mod impls {
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
}
}
}
+
+#[cfg(not(bootstrap))]
+mod impls {
+ use crate::marker::Tuple;
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
+ impl<A: Tuple, F: ?Sized> const Fn<A> for &F
+ where
+ F: ~const Fn<A>,
+ {
+ extern "rust-call" fn call(&self, args: A) -> F::Output {
+ (**self).call(args)
+ }
+ }
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
+ impl<A: Tuple, F: ?Sized> const FnMut<A> for &F
+ where
+ F: ~const Fn<A>,
+ {
+ extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
+ (**self).call(args)
+ }
+ }
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
+ impl<A: Tuple, F: ?Sized> const FnOnce<A> for &F
+ where
+ F: ~const Fn<A>,
+ {
+ type Output = F::Output;
+
+ extern "rust-call" fn call_once(self, args: A) -> F::Output {
+ (*self).call(args)
+ }
+ }
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
+ impl<A: Tuple, F: ?Sized> const FnMut<A> for &mut F
+ where
+ F: ~const FnMut<A>,
+ {
+ extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output {
+ (*self).call_mut(args)
+ }
+ }
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_fn_trait_ref_impls", issue = "101803")]
+ impl<A: Tuple, F: ?Sized> const FnOnce<A> for &mut F
+ where
+ F: ~const FnMut<A>,
+ {
+ type Output = F::Output;
+ extern "rust-call" fn call_once(self, args: A) -> F::Output {
+ (*self).call_mut(args)
+ }
+ }
+}
#[inline]
pub const unsafe fn new_unchecked(start: usize, end: usize) -> Self {
// SAFETY: comparisons on usize are pure
- unsafe { assert_unsafe_precondition!((start: usize, end: usize) => start <= end) };
+ unsafe {
+ assert_unsafe_precondition!(
+ "IndexRange::new_unchecked requires `start <= end`",
+ (start: usize, end: usize) => start <= end
+ )
+ };
IndexRange { start, end }
}
// Do not `doc(no_inline)` so that they become doc items on their own
// (no public module for them to be re-exported from).
+#[cfg(not(bootstrap))]
+#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
+pub use crate::macros::builtin::alloc_error_handler;
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
pub use crate::macros::builtin::{bench, derive, global_allocator, test, test_case};
#[inline]
pub const unsafe fn new_unchecked(align: usize) -> Self {
// SAFETY: Precondition passed to the caller.
- unsafe { assert_unsafe_precondition!((align: usize) => align.is_power_of_two()) };
+ unsafe {
+ assert_unsafe_precondition!(
+ "Alignment::new_unchecked requires a power of two",
+ (align: usize) => align.is_power_of_two()
+ )
+ };
// SAFETY: By precondition, this must be a power of two, and
// our variants encompass all possible powers of two.
// SAFETY: The comparison has no side-effects, and the intrinsic
// does this check internally in the CTFE implementation.
unsafe {
- assert_unsafe_precondition!([T](this: *const T, origin: *const T) => this >= origin)
+ assert_unsafe_precondition!(
+ "ptr::sub_ptr requires `this >= origin`",
+ [T](this: *const T, origin: *const T) => this >= origin
+ )
};
let pointee_size = mem::size_of::<T>();
/// Convert an address back to a pointer, picking up a previously 'exposed' provenance.
///
/// This is equivalent to `addr as *const T`. The provenance of the returned pointer is that of *any*
-/// pointer that was previously passed to [`expose_addr`][pointer::expose_addr] or a `ptr as usize`
-/// cast. If there is no previously 'exposed' provenance that justifies the way this pointer will be
-/// used, the program has undefined behavior. Note that there is no algorithm that decides which
-/// provenance will be used. You can think of this as "guessing" the right provenance, and the guess
-/// will be "maximally in your favor", in the sense that if there is any way to avoid undefined
-/// behavior, then that is the guess that will be taken.
+/// pointer that was previously exposed by passing it to [`expose_addr`][pointer::expose_addr],
+/// or a `ptr as usize` cast. In addition, memory which is outside the control of the Rust abstract
+/// machine (MMIO registers, for example) is always considered to be exposed, so long as this memory
+/// is disjoint from memory that will be used by the abstract machine such as the stack, heap,
+/// and statics.
+///
+/// If there is no 'exposed' provenance that justifies the way this pointer will be used,
+/// the program has undefined behavior. In particular, the aliasing rules still apply: pointers
+/// and references that have been invalidated due to aliasing accesses cannot be used any more,
+/// even if they have been exposed!
+///
+/// Note that there is no algorithm that decides which provenance will be used. You can think of this
+/// as "guessing" the right provenance, and the guess will be "maximally in your favor", in the sense
+/// that if there is any way to avoid undefined behavior (while upholding all aliasing requirements),
+/// then that is the guess that will be taken.
///
/// On platforms with multiple address spaces, it is your responsibility to ensure that the
/// address makes sense in the address space that this pointer will be used with.
// SAFETY: the caller must guarantee that `x` and `y` are
// valid for writes and properly aligned.
unsafe {
- assert_unsafe_precondition!([T](x: *mut T, y: *mut T, count: usize) =>
+ assert_unsafe_precondition!(
+ "ptr::swap_nonoverlapping requires that both pointer arguments are aligned and non-null \
+ and the specified memory ranges do not overlap",
+ [T](x: *mut T, y: *mut T, count: usize) =>
is_aligned_and_not_null(x)
&& is_aligned_and_not_null(y)
&& is_nonoverlapping(x, y, count)
// and cannot overlap `src` since `dst` must point to a distinct
// allocated object.
unsafe {
- assert_unsafe_precondition!([T](dst: *mut T) => is_aligned_and_not_null(dst));
+ assert_unsafe_precondition!(
+ "ptr::replace requires that the pointer argument is aligned and non-null",
+ [T](dst: *mut T) => is_aligned_and_not_null(dst)
+ );
mem::swap(&mut *dst, &mut src); // cannot overlap
}
src
// Also, since we just wrote a valid value into `tmp`, it is guaranteed
// to be properly initialized.
unsafe {
- assert_unsafe_precondition!([T](src: *const T) => is_aligned_and_not_null(src));
+ assert_unsafe_precondition!(
+ "ptr::read requires that the pointer argument is aligned and non-null",
+ [T](src: *const T) => is_aligned_and_not_null(src)
+ );
copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
tmp.assume_init()
}
// `dst` cannot overlap `src` because the caller has mutable access
// to `dst` while `src` is owned by this function.
unsafe {
- assert_unsafe_precondition!([T](dst: *mut T) => is_aligned_and_not_null(dst));
+ assert_unsafe_precondition!(
+ "ptr::write requires that the pointer argument is aligned and non-null",
+ [T](dst: *mut T) => is_aligned_and_not_null(dst)
+ );
copy_nonoverlapping(&src as *const T, dst, 1);
intrinsics::forget(src);
}
pub unsafe fn read_volatile<T>(src: *const T) -> T {
// SAFETY: the caller must uphold the safety contract for `volatile_load`.
unsafe {
- assert_unsafe_precondition!([T](src: *const T) => is_aligned_and_not_null(src));
+ assert_unsafe_precondition!(
+ "ptr::read_volatile requires that the pointer argument is aligned and non-null",
+ [T](src: *const T) => is_aligned_and_not_null(src)
+ );
intrinsics::volatile_load(src)
}
}
pub unsafe fn write_volatile<T>(dst: *mut T, src: T) {
// SAFETY: the caller must uphold the safety contract for `volatile_store`.
unsafe {
- assert_unsafe_precondition!([T](dst: *mut T) => is_aligned_and_not_null(dst));
+ assert_unsafe_precondition!(
+ "ptr::write_volatile requires that the pointer argument is aligned and non-null",
+ [T](dst: *mut T) => is_aligned_and_not_null(dst)
+ );
intrinsics::volatile_store(dst, src);
}
}
pub const unsafe fn new_unchecked(ptr: *mut T) -> Self {
// SAFETY: the caller must guarantee that `ptr` is non-null.
unsafe {
- assert_unsafe_precondition!([T: ?Sized](ptr: *mut T) => !ptr.is_null());
+ assert_unsafe_precondition!("NonNull::new_unchecked requires that the pointer is non-null", [T: ?Sized](ptr: *mut T) => !ptr.is_null());
NonNull { pointer: ptr as _ }
}
}
// `self` is in bounds of `slice` so `self` cannot overflow an `isize`,
// so the call to `add` is safe.
unsafe {
- assert_unsafe_precondition!([T](this: usize, slice: *const [T]) => this < slice.len());
+ assert_unsafe_precondition!(
+ "slice::get_unchecked requires that the index is within the slice",
+ [T](this: usize, slice: *const [T]) => this < slice.len()
+ );
slice.as_ptr().add(self)
}
}
let this = self;
// SAFETY: see comments for `get_unchecked` above.
unsafe {
- assert_unsafe_precondition!([T](this: usize, slice: *mut [T]) => this < slice.len());
+ assert_unsafe_precondition!(
+ "slice::get_unchecked_mut requires that the index is within the slice",
+ [T](this: usize, slice: *mut [T]) => this < slice.len()
+ );
slice.as_mut_ptr().add(self)
}
}
// so the call to `add` is safe.
unsafe {
- assert_unsafe_precondition!([T](end: usize, slice: *const [T]) =>
- end <= slice.len());
+ assert_unsafe_precondition!(
+ "slice::get_unchecked requires that the index is within the slice",
+ [T](end: usize, slice: *const [T]) => end <= slice.len()
+ );
ptr::slice_from_raw_parts(slice.as_ptr().add(self.start()), self.len())
}
}
let end = self.end();
// SAFETY: see comments for `get_unchecked` above.
unsafe {
- assert_unsafe_precondition!([T](end: usize, slice: *mut [T]) =>
- end <= slice.len());
+ assert_unsafe_precondition!(
+ "slice::get_unchecked_mut requires that the index is within the slice",
+ [T](end: usize, slice: *mut [T]) => end <= slice.len()
+ );
ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start()), self.len())
}
}
// so the call to `add` is safe.
unsafe {
- assert_unsafe_precondition!([T](this: ops::Range<usize>, slice: *const [T]) =>
- this.end >= this.start && this.end <= slice.len());
+ assert_unsafe_precondition!(
+ "slice::get_unchecked requires that the range is within the slice",
+ [T](this: ops::Range<usize>, slice: *const [T]) =>
+ this.end >= this.start && this.end <= slice.len()
+ );
ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start)
}
}
let this = ops::Range { start: self.start, end: self.end };
// SAFETY: see comments for `get_unchecked` above.
unsafe {
- assert_unsafe_precondition!([T](this: ops::Range<usize>, slice: *mut [T]) =>
- this.end >= this.start && this.end <= slice.len());
+ assert_unsafe_precondition!(
+ "slice::get_unchecked_mut requires that the range is within the slice",
+ [T](this: ops::Range<usize>, slice: *mut [T]) =>
+ this.end >= this.start && this.end <= slice.len()
+ );
ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start)
}
}
let ptr = this.as_mut_ptr();
// SAFETY: caller has to guarantee that `a < self.len()` and `b < self.len()`
unsafe {
- assert_unsafe_precondition!([T](a: usize, b: usize, this: &mut [T]) => a < this.len() && b < this.len());
+ assert_unsafe_precondition!(
+ "slice::swap_unchecked requires that the indices are within the slice",
+ [T](a: usize, b: usize, this: &mut [T]) => a < this.len() && b < this.len()
+ );
ptr::swap(ptr.add(a), ptr.add(b));
}
}
let this = self;
// SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length
let new_len = unsafe {
- assert_unsafe_precondition!([T](this: &[T], N: usize) => N != 0 && this.len() % N == 0);
+ assert_unsafe_precondition!(
+ "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks",
+ [T](this: &[T], N: usize) => N != 0 && this.len() % N == 0
+ );
exact_div(self.len(), N)
};
// SAFETY: We cast a slice of `new_len * N` elements into
let this = &*self;
// SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length
let new_len = unsafe {
- assert_unsafe_precondition!([T](this: &[T], N: usize) => N != 0 && this.len() % N == 0);
+ assert_unsafe_precondition!(
+ "slice::as_chunks_unchecked_mut requires `N != 0` and the slice to split exactly into `N`-element chunks",
+ [T](this: &[T], N: usize) => N != 0 && this.len() % N == 0
+ );
exact_div(this.len(), N)
};
// SAFETY: We cast a slice of `new_len * N` elements into
// `[ptr; mid]` and `[mid; len]` are not overlapping, so returning a mutable reference
// is fine.
unsafe {
- assert_unsafe_precondition!((mid: usize, len: usize) => mid <= len);
+ assert_unsafe_precondition!(
+ "slice::split_at_mut_unchecked requires the index to be within the slice",
+ (mid: usize, len: usize) => mid <= len
+ );
(from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid))
}
}
}
}
- /// Transmute the slice to a slice of another type, ensuring alignment of the types is
- /// maintained.
+ /// Transmute the mutable slice to a mutable slice of another type, ensuring alignment of the
+ /// types is maintained.
///
/// This method splits the slice into three distinct slices: prefix, correctly aligned middle
/// slice of a new type, and the suffix slice. The method may make the middle slice the greatest
pub const unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] {
// SAFETY: the caller must uphold the safety contract for `from_raw_parts`.
unsafe {
- assert_unsafe_precondition!([T](data: *const T, len: usize) =>
- is_aligned_and_not_null(data) && is_valid_allocation_size::<T>(len)
+ assert_unsafe_precondition!(
+ "slice::from_raw_parts requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`",
+ [T](data: *const T, len: usize) => is_aligned_and_not_null(data)
+ && is_valid_allocation_size::<T>(len)
);
&*ptr::slice_from_raw_parts(data, len)
}
pub const unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] {
// SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`.
unsafe {
- assert_unsafe_precondition!([T](data: *mut T, len: usize) =>
- is_aligned_and_not_null(data) && is_valid_allocation_size::<T>(len)
+ assert_unsafe_precondition!(
+ "slice::from_raw_parts_mut requires the pointer to be aligned and non-null, and the total size of the slice not to exceed `isize::MAX`",
+ [T](data: *mut T, len: usize) => is_aligned_and_not_null(data)
+ && is_valid_allocation_size::<T>(len)
);
&mut *ptr::slice_from_raw_parts_mut(data, len)
}
assert_ne!(type_name_of_val(Velocity), type_name_of_val(Velocity(0.0, -9.8)),);
}
+#[cfg(not(bootstrap))]
+#[test]
+fn dyn_type_name() {
+ trait Foo {
+ type Bar;
+ }
+
+ assert_eq!(
+ "dyn core::ops::function::Fn(i32, i32) -> i32",
+ std::any::type_name::<dyn Fn(i32, i32) -> i32>()
+ );
+ assert_eq!(
+ "dyn coretests::any::dyn_type_name::Foo<Bar = i32> \
+ + core::marker::Send + core::marker::Sync",
+ std::any::type_name::<dyn Foo<Bar = i32> + Send + Sync>()
+ );
+}
+
// Test the `Provider` API.
struct SomeConcreteType {
let result =
(0..10).map(|_| CountDrop::new(&count)).array_chunks::<3>().fold(0, |acc, _item| acc + 1);
assert_eq!(result, 3);
- assert_eq!(count.get(), 10);
+ // fold impls may or may not process the remainder
+ assert!(count.get() <= 10 && count.get() >= 9);
}
#[test]
#![feature(bigint_helper_methods)]
#![feature(cell_update)]
#![feature(const_assume)]
+#![feature(const_align_of_val_raw)]
#![feature(const_black_box)]
#![feature(const_bool_to_option)]
#![feature(const_caller_location)]
#![feature(try_find)]
#![feature(inline_const)]
#![feature(is_sorted)]
+#![feature(layout_for_ptr)]
#![feature(pattern)]
#![feature(pin_macro)]
#![feature(sort_internals)]
#![feature(try_trait_v2)]
#![feature(slice_internals)]
#![feature(slice_partition_dedup)]
-#![feature(int_log)]
#![feature(iter_advance_by)]
#![feature(iter_array_chunks)]
#![feature(iter_collect_into)]
use core::mem::*;
+use core::ptr;
#[cfg(panic = "unwind")]
use std::rc::Rc;
assert_eq!(align_of_val(&1u32), 4);
}
+#[test]
+#[cfg(not(bootstrap))] // stage 0 doesn't have the fix yet, so the test fails
+fn align_of_val_raw_packed() {
+ #[repr(C, packed)]
+ struct B {
+ f: [u32],
+ }
+ let storage = [0u8; 4];
+ let b: *const B = ptr::from_raw_parts(storage.as_ptr().cast(), 1);
+ assert_eq!(unsafe { align_of_val_raw(b) }, 1);
+
+ const ALIGN_OF_VAL_RAW: usize = {
+ let storage = [0u8; 4];
+ let b: *const B = ptr::from_raw_parts(storage.as_ptr().cast(), 1);
+ unsafe { align_of_val_raw(b) }
+ };
+ assert_eq!(ALIGN_OF_VAL_RAW, 1);
+}
+
#[test]
fn test_swap() {
let mut x = 31337;
[dependencies]
alloc = { path = "../alloc" }
-cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] }
+cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
core = { path = "../core" }
libc = { version = "0.2", default-features = false }
compiler_builtins = "0.1.0"
libc = { version = "0.2", default-features = false }
unwind = { path = "../unwind" }
compiler_builtins = "0.1.0"
-cfg-if = "0.1.8"
+cfg-if = "1.0"
name: b"rust_panic\0".as_ptr(),
};
+// NOTE(nbdd0121): The `canary` field will be part of stable ABI after `c_unwind` stabilization.
+#[repr(C)]
struct Exception {
+ // See `gcc.rs` on why this is present. We already have a static here so just use it.
+ canary: *const TypeInfo,
+
// This is necessary because C++ code can capture our exception with
// std::exception_ptr and rethrow it multiple times, possibly even in
// another thread.
let catch_data = &*(ptr as *mut CatchData);
let adjusted_ptr = __cxa_begin_catch(catch_data.ptr as *mut libc::c_void) as *mut Exception;
- let out = if catch_data.is_rust_panic {
- let was_caught = (*adjusted_ptr).caught.swap(true, Ordering::SeqCst);
- if was_caught {
- // Since cleanup() isn't allowed to panic, we just abort instead.
- intrinsics::abort();
- }
- (*adjusted_ptr).data.take().unwrap()
- } else {
+ if !catch_data.is_rust_panic {
super::__rust_foreign_exception();
- };
+ }
+
+ let canary = ptr::addr_of!((*adjusted_ptr).canary).read();
+ if !ptr::eq(canary, &EXCEPTION_TYPE_INFO) {
+ super::__rust_foreign_exception();
+ }
+
+ let was_caught = (*adjusted_ptr).caught.swap(true, Ordering::SeqCst);
+ if was_caught {
+ // Since cleanup() isn't allowed to panic, we just abort instead.
+ intrinsics::abort();
+ }
+ let out = (*adjusted_ptr).data.take().unwrap();
__cxa_end_catch();
out
}
pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
- let sz = mem::size_of_val(&data);
- let exception = __cxa_allocate_exception(sz) as *mut Exception;
+ let exception = __cxa_allocate_exception(mem::size_of::<Exception>()) as *mut Exception;
if exception.is_null() {
return uw::_URC_FATAL_PHASE1_ERROR as u32;
}
- ptr::write(exception, Exception { caught: AtomicBool::new(false), data: Some(data) });
+ ptr::write(
+ exception,
+ Exception {
+ canary: &EXCEPTION_TYPE_INFO,
+ caught: AtomicBool::new(false),
+ data: Some(data),
+ },
+ );
__cxa_throw(exception as *mut _, &EXCEPTION_TYPE_INFO, exception_cleanup);
}
use alloc::boxed::Box;
use core::any::Any;
+use core::ptr;
use unwind as uw;
+// In case where multiple copies of std exist in a single process,
+// we use address of this static variable to distinguish an exception raised by
+// this copy and some other copy (which needs to be treated as foreign exception).
+static CANARY: u8 = 0;
+
+// NOTE(nbdd0121)
+// Once `c_unwind` feature is stabilized, there will be ABI stability requirement
+// on this struct. The first two field must be `_Unwind_Exception` and `canary`,
+// as it may be accessed by a different version of the std with a different compiler.
#[repr(C)]
struct Exception {
_uwe: uw::_Unwind_Exception,
+ canary: *const u8,
cause: Box<dyn Any + Send>,
}
exception_cleanup,
private: [0; uw::unwinder_private_data_size],
},
+ canary: &CANARY,
cause: data,
});
let exception_param = Box::into_raw(exception) as *mut uw::_Unwind_Exception;
if (*exception).exception_class != rust_exception_class() {
uw::_Unwind_DeleteException(exception);
super::__rust_foreign_exception();
- } else {
- let exception = Box::from_raw(exception as *mut Exception);
- exception.cause
}
+
+ let exception = exception.cast::<Exception>();
+ // Just access the canary field, avoid accessing the entire `Exception` as
+ // it can be a foreign Rust exception.
+ let canary = ptr::addr_of!((*exception).canary).read();
+ if !ptr::eq(canary, &CANARY) {
+ // A foreign Rust exception, treat it slightly differently from other
+ // foreign exceptions, because call into `_Unwind_DeleteException` will
+ // call into `__rust_drop_panic` which produces a confusing
+ // "Rust panic must be rethrown" message.
+ super::__rust_foreign_exception();
+ }
+
+ let exception = Box::from_raw(exception as *mut Exception);
+ exception.cause
}
// Rust's exception class identifier. This is used by personality routines to
use alloc::boxed::Box;
use core::any::Any;
use core::mem::{self, ManuallyDrop};
+use core::ptr;
use libc::{c_int, c_uint, c_void};
+// NOTE(nbdd0121): The `canary` field will be part of stable ABI after `c_unwind` stabilization.
+#[repr(C)]
struct Exception {
+ // See `gcc.rs` on why this is present. We already have a static here so just use it.
+ canary: *const _TypeDescriptor,
+
// This needs to be an Option because we catch the exception by reference
// and its destructor is executed by the C++ runtime. When we take the Box
// out of the exception, we need to leave the exception in a valid state
macro_rules! define_cleanup {
($abi:tt $abi2:tt) => {
unsafe extern $abi fn exception_cleanup(e: *mut Exception) {
- if let Exception { data: Some(b) } = e.read() {
+ if let Exception { data: Some(b), .. } = e.read() {
drop(b);
super::__rust_drop_panic();
}
// The ManuallyDrop is needed here since we don't want Exception to be
// dropped when unwinding. Instead it will be dropped by exception_cleanup
// which is invoked by the C++ runtime.
- let mut exception = ManuallyDrop::new(Exception { data: Some(data) });
+ let mut exception = ManuallyDrop::new(Exception { canary: &TYPE_DESCRIPTOR, data: Some(data) });
let throw_ptr = &mut exception as *mut _ as *mut _;
// This... may seems surprising, and justifiably so. On 32-bit MSVC the
// __rust_try. This happens when a non-Rust foreign exception is caught.
if payload.is_null() {
super::__rust_foreign_exception();
- } else {
- let exception = &mut *(payload as *mut Exception);
- exception.data.take().unwrap()
}
+ let exception = payload as *mut Exception;
+ let canary = ptr::addr_of!((*exception).canary).read();
+ if !ptr::eq(canary, &TYPE_DESCRIPTOR) {
+ // A foreign Rust exception.
+ super::__rust_foreign_exception();
+ }
+ (*exception).data.take().unwrap()
}
std_detect = { path = "../stdarch/crates/std_detect", default-features = false, features = ['rustc-dep-of-std'] }
# Dependencies of the `backtrace` crate
-addr2line = { version = "0.16.0", optional = true, default-features = false }
+addr2line = { version = "0.17.0", optional = true, default-features = false }
rustc-demangle = { version = "0.1.21", features = ['rustc-dep-of-std'] }
-miniz_oxide = { version = "0.4.0", optional = true, default-features = false }
+miniz_oxide = { version = "0.5.0", optional = true, default-features = false }
[dependencies.object]
-version = "0.26.1"
+version = "0.29.0"
optional = true
default-features = false
features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive']
/// Tries to reserve capacity for at least `additional` more elements to be inserted
/// in the `HashMap`. The collection may reserve more space to speculatively
- /// avoid frequent reallocations. After calling `reserve`,
+ /// avoid frequent reallocations. After calling `try_reserve`,
/// capacity will be greater than or equal to `self.len() + additional` if
/// it returns `Ok(())`.
/// Does nothing if capacity is already sufficient.
/// Tries to reserve capacity for at least `additional` more elements to be inserted
/// in the `HashSet`. The collection may reserve more space to speculatively
- /// avoid frequent reallocations. After calling `reserve`,
+ /// avoid frequent reallocations. After calling `try_reserve`,
/// capacity will be greater than or equal to `self.len() + additional` if
/// it returns `Ok(())`.
/// Does nothing if capacity is already sufficient.
/// ```
/// let f = 3.3_f32;
/// let g = -3.3_f32;
+ /// let h = -3.7_f32;
///
/// assert_eq!(f.round(), 3.0);
/// assert_eq!(g.round(), -3.0);
+ /// assert_eq!(h.round(), -4.0);
/// ```
#[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
/// This result is not an element of the function's codomain, but it is the
/// closest floating point number in the real numbers and thus fulfills the
/// property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)`
- /// approximatively.
+ /// approximately.
///
/// # Examples
///
/// ```
/// let f = 3.3_f64;
/// let g = -3.3_f64;
+ /// let h = -3.7_f64;
///
/// assert_eq!(f.round(), 3.0);
/// assert_eq!(g.round(), -3.0);
+ /// assert_eq!(h.round(), -4.0);
/// ```
#[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
/// This result is not an element of the function's codomain, but it is the
/// closest floating point number in the real numbers and thus fulfills the
/// property `self == self.div_euclid(rhs) * rhs + self.rem_euclid(rhs)`
- /// approximatively.
+ /// approximately.
///
/// # Examples
///
//! [`Ipv6Addr`] are respectively IPv4 and IPv6 addresses
//! * [`SocketAddr`] represents socket addresses of either IPv4 or IPv6; [`SocketAddrV4`]
//! and [`SocketAddrV6`] are respectively IPv4 and IPv6 socket addresses
-//! * [`ToSocketAddrs`] is a trait that used for generic address resolution when interacting
+//! * [`ToSocketAddrs`] is a trait that is used for generic address resolution when interacting
//! with networking objects like [`TcpListener`], [`TcpStream`] or [`UdpSocket`]
//! * Other types are return or parameter types for various methods in this module
//!
// Do not `doc(no_inline)` so that they become doc items on their own
// (no public module for them to be re-exported from).
+#[cfg(not(bootstrap))]
+#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
+pub use core::prelude::v1::alloc_error_handler;
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
pub use core::prelude::v1::{bench, derive, global_allocator, test, test_case};
//! method, and see the method for more information about it. Due to this
//! caveat, this queue might not be appropriate for all use-cases.
-// https://www.1024cores.net/home/lock-free-algorithms
-// /queues/non-intrusive-mpsc-node-based-queue
+// The original implementation is based off:
+// https://www.1024cores.net/home/lock-free-algorithms/queues/non-intrusive-mpsc-node-based-queue
+//
+// Note that back when the code was imported, it was licensed under the BSD-2-Clause license:
+// http://web.archive.org/web/20110411011612/https://www.1024cores.net/home/lock-free-algorithms/queues/unbounded-spsc-queue
+//
+// The original author of the code agreed to relicense it under `MIT OR Apache-2.0` in 2017, so as
+// of today the license of this file is the same as the rest of the codebase:
+// https://github.com/rust-lang/rust/pull/42149
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests;
//! concurrently between two threads. This data structure is safe to use and
//! enforces the semantics that there is one pusher and one popper.
+// The original implementation is based off:
// https://www.1024cores.net/home/lock-free-algorithms/queues/unbounded-spsc-queue
+//
+// Note that back when the code was imported, it was licensed under the BSD-2-Clause license:
+// http://web.archive.org/web/20110411011612/https://www.1024cores.net/home/lock-free-algorithms/queues/unbounded-spsc-queue
+//
+// The original author of the code agreed to relicense it under `MIT OR Apache-2.0` in 2017, so as
+// of today the license of this file is the same as the rest of the codebase:
+// https://github.com/rust-lang/rust/pull/42149
#[cfg(all(test, not(target_os = "emscripten")))]
mod tests;
+// miri has some special hacks here that make things unused.
+#![cfg_attr(miri, allow(unused))]
+
use crate::os::unix::prelude::*;
use crate::ffi::{CStr, OsStr, OsString};
target_os = "fuchsia",
target_os = "redox"
)))]
- #[cfg_attr(miri, allow(unused))]
fn name_cstr(&self) -> &CStr {
unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }
}
target_os = "fuchsia",
target_os = "redox"
))]
- #[cfg_attr(miri, allow(unused))]
fn name_cstr(&self) -> &CStr {
&self.name
}
pub type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES;
pub type LPSTARTUPINFO = *mut STARTUPINFO;
pub type LPVOID = *mut c_void;
+pub type LPCVOID = *const c_void;
pub type LPWCH = *mut WCHAR;
pub type LPWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW;
pub type LPWSADATA = *mut WSADATA;
pub type LPOVERLAPPED_COMPLETION_ROUTINE = unsafe extern "system" fn(
dwErrorCode: DWORD,
- dwNumberOfBytesTransfered: DWORD,
+ dwNumberOfBytesTransferred: DWORD,
lpOverlapped: *mut OVERLAPPED,
);
pub tv_usec: c_long,
}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct CONSOLE_READCONSOLE_CONTROL {
+ pub nLength: ULONG,
+ pub nInitialChars: ULONG,
+ pub dwCtrlWakeupMask: ULONG,
+ pub dwControlKeyState: ULONG,
+}
+pub type PCONSOLE_READCONSOLE_CONTROL = *mut CONSOLE_READCONSOLE_CONTROL;
+
// Desktop specific functions & types
cfg_if::cfg_if! {
if #[cfg(not(target_vendor = "uwp"))] {
pub type PVECTORED_EXCEPTION_HANDLER =
extern "system" fn(ExceptionInfo: *mut EXCEPTION_POINTERS) -> LONG;
- #[repr(C)]
- #[derive(Copy, Clone)]
- pub struct CONSOLE_READCONSOLE_CONTROL {
- pub nLength: ULONG,
- pub nInitialChars: ULONG,
- pub dwCtrlWakeupMask: ULONG,
- pub dwControlKeyState: ULONG,
- }
-
- pub type PCONSOLE_READCONSOLE_CONTROL = *mut CONSOLE_READCONSOLE_CONTROL;
-
#[repr(C)]
pub struct BY_HANDLE_FILE_INFORMATION {
pub dwFileAttributes: DWORD,
}
pub type LPBY_HANDLE_FILE_INFORMATION = *mut BY_HANDLE_FILE_INFORMATION;
- pub type LPCVOID = *const c_void;
pub const HANDLE_FLAG_INHERIT: DWORD = 0x00000001;
#[link(name = "kernel32")]
extern "system" {
- // Functions forbidden when targeting UWP
- pub fn ReadConsoleW(
- hConsoleInput: HANDLE,
- lpBuffer: LPVOID,
- nNumberOfCharsToRead: DWORD,
- lpNumberOfCharsRead: LPDWORD,
- pInputControl: PCONSOLE_READCONSOLE_CONTROL,
- ) -> BOOL;
-
- pub fn WriteConsoleW(
- hConsoleOutput: HANDLE,
- lpBuffer: LPCVOID,
- nNumberOfCharsToWrite: DWORD,
- lpNumberOfCharsWritten: LPDWORD,
- lpReserved: LPVOID,
- ) -> BOOL;
-
- pub fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL;
// Allowed but unused by UWP
pub fn GetFileInformationByHandle(
hFile: HANDLE,
extern "system" {
pub fn GetCurrentProcessId() -> DWORD;
+ pub fn ReadConsoleW(
+ hConsoleInput: HANDLE,
+ lpBuffer: LPVOID,
+ nNumberOfCharsToRead: DWORD,
+ lpNumberOfCharsRead: LPDWORD,
+ pInputControl: PCONSOLE_READCONSOLE_CONTROL,
+ ) -> BOOL;
+ pub fn WriteConsoleW(
+ hConsoleOutput: HANDLE,
+ lpBuffer: LPCVOID,
+ nNumberOfCharsToWrite: DWORD,
+ lpNumberOfCharsWritten: LPDWORD,
+ lpReserved: LPVOID,
+ ) -> BOOL;
+ pub fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL;
+
pub fn GetSystemDirectoryW(lpBuffer: LPWSTR, uSize: UINT) -> UINT;
pub fn RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL;
pub fn SetFileAttributesW(lpFileName: LPCWSTR, dwFileAttributes: DWORD) -> BOOL;
pub mod pipe;
pub mod process;
pub mod rand;
+pub mod stdio;
pub mod thread;
pub mod thread_local_dtor;
pub mod thread_local_key;
pub mod time;
cfg_if::cfg_if! {
if #[cfg(not(target_vendor = "uwp"))] {
- pub mod stdio;
pub mod stack_overflow;
} else {
- pub mod stdio_uwp;
pub mod stack_overflow_uwp;
- pub use self::stdio_uwp as stdio;
pub use self::stack_overflow_uwp as stack_overflow;
}
}
let mut async_result: Option<AsyncResult> = None;
struct AsyncResult {
error: u32,
- transfered: u32,
+ transferred: u32,
}
// STEP 3: The callback.
unsafe extern "system" fn callback(
dwErrorCode: u32,
- dwNumberOfBytesTransfered: u32,
+ dwNumberOfBytesTransferred: u32,
lpOverlapped: *mut c::OVERLAPPED,
) {
// Set `async_result` using a pointer smuggled through `hEvent`.
- let result = AsyncResult { error: dwErrorCode, transfered: dwNumberOfBytesTransfered };
+ let result =
+ AsyncResult { error: dwErrorCode, transferred: dwNumberOfBytesTransferred };
*(*lpOverlapped).hEvent.cast::<Option<AsyncResult>>() = Some(result);
}
// STEP 4: Return the result.
// `async_result` is always `Some` at this point
match result.error {
- c::ERROR_SUCCESS => Ok(result.transfered as usize),
+ c::ERROR_SUCCESS => Ok(result.transferred as usize),
error => Err(io::Error::from_raw_os_error(error as _)),
}
}
+++ /dev/null
-#![unstable(issue = "none", feature = "windows_stdio")]
-
-use crate::io;
-use crate::mem::ManuallyDrop;
-use crate::os::windows::io::FromRawHandle;
-use crate::sys::c;
-use crate::sys::handle::Handle;
-
-pub struct Stdin {}
-pub struct Stdout;
-pub struct Stderr;
-
-const MAX_BUFFER_SIZE: usize = 8192;
-pub const STDIN_BUF_SIZE: usize = MAX_BUFFER_SIZE / 2 * 3;
-
-pub fn get_handle(handle_id: c::DWORD) -> io::Result<c::HANDLE> {
- let handle = unsafe { c::GetStdHandle(handle_id) };
- if handle == c::INVALID_HANDLE_VALUE {
- Err(io::Error::last_os_error())
- } else if handle.is_null() {
- Err(io::Error::from_raw_os_error(c::ERROR_INVALID_HANDLE as i32))
- } else {
- Ok(handle)
- }
-}
-
-fn write(handle_id: c::DWORD, data: &[u8]) -> io::Result<usize> {
- let handle = get_handle(handle_id)?;
- // SAFETY: The handle returned from `get_handle` must be valid and non-null.
- let handle = unsafe { Handle::from_raw_handle(handle) };
- ManuallyDrop::new(handle).write(data)
-}
-
-impl Stdin {
- pub const fn new() -> Stdin {
- Stdin {}
- }
-}
-
-impl io::Read for Stdin {
- fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- let handle = get_handle(c::STD_INPUT_HANDLE)?;
- // SAFETY: The handle returned from `get_handle` must be valid and non-null.
- let handle = unsafe { Handle::from_raw_handle(handle) };
- ManuallyDrop::new(handle).read(buf)
- }
-}
-
-impl Stdout {
- pub const fn new() -> Stdout {
- Stdout
- }
-}
-
-impl io::Write for Stdout {
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- write(c::STD_OUTPUT_HANDLE, buf)
- }
-
- fn flush(&mut self) -> io::Result<()> {
- Ok(())
- }
-}
-
-impl Stderr {
- pub const fn new() -> Stderr {
- Stderr
- }
-}
-
-impl io::Write for Stderr {
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- write(c::STD_ERROR_HANDLE, buf)
- }
-
- fn flush(&mut self) -> io::Result<()> {
- Ok(())
- }
-}
-
-pub fn is_ebadf(err: &io::Error) -> bool {
- err.raw_os_error() == Some(c::ERROR_INVALID_HANDLE as i32)
-}
-
-pub fn panic_output() -> Option<impl io::Write> {
- Some(Stderr::new())
-}
out: &mut dyn OutputFormatter,
) -> io::Result<()> {
match (*event).clone() {
- TestEvent::TeFiltered(ref filtered_tests, shuffle_seed) => {
- st.total = filtered_tests.len();
- out.write_run_start(filtered_tests.len(), shuffle_seed)?;
+ TestEvent::TeFiltered(filtered_tests, shuffle_seed) => {
+ st.total = filtered_tests;
+ out.write_run_start(filtered_tests, shuffle_seed)?;
}
TestEvent::TeFilteredOut(filtered_out) => {
st.filtered_out = filtered_out;
#[derive(Debug, Clone)]
pub enum TestEvent {
- TeFiltered(Vec<TestDesc>, Option<u64>),
+ TeFiltered(usize, Option<u64>),
TeWait(TestDesc),
TeResult(CompletedTest),
TeTimeout(TestDesc),
#![feature(is_terminal)]
#![feature(staged_api)]
#![feature(process_exitcode_internals)]
+#![feature(panic_can_unwind)]
#![feature(test)]
// Public reexports
cli::{parse_opts, TestOpts},
filter_tests,
helpers::metrics::{Metric, MetricMap},
- options::{Concurrent, Options, RunIgnored, RunStrategy, ShouldPanic},
+ options::{Options, RunIgnored, RunStrategy, ShouldPanic},
run_test, test_main, test_main_static,
test_result::{TestResult, TrFailed, TrFailedMsg, TrIgnored, TrOk},
time::{TestExecTime, TestTimeOptions},
collections::VecDeque,
env, io,
io::prelude::Write,
+ mem::ManuallyDrop,
panic::{self, catch_unwind, AssertUnwindSafe, PanicInfo},
process::{self, Command, Termination},
sync::mpsc::{channel, Sender},
use helpers::concurrency::get_concurrency;
use helpers::exit_code::get_exit_code;
use helpers::shuffle::{get_shuffle_seed, shuffle_tests};
-use options::{Concurrent, RunStrategy};
+use options::RunStrategy;
use test_result::*;
use time::TestExecTime;
process::exit(ERROR_EXIT_CODE);
}
} else {
+ if !opts.nocapture {
+ // If we encounter a non-unwinding panic, flush any captured output from the current test,
+ // and stop capturing output to ensure that the non-unwinding panic message is visible.
+ // We also acquire the locks for both output streams to prevent output from other threads
+ // from interleaving with the panic message or appearing after it.
+ let builtin_panic_hook = panic::take_hook();
+ let hook = Box::new({
+ move |info: &'_ PanicInfo<'_>| {
+ if !info.can_unwind() {
+ std::mem::forget(std::io::stderr().lock());
+ let mut stdout = ManuallyDrop::new(std::io::stdout().lock());
+ if let Some(captured) = io::set_output_capture(None) {
+ if let Ok(data) = captured.lock() {
+ let _ = stdout.write_all(&data);
+ let _ = stdout.flush();
+ }
+ }
+ }
+ builtin_panic_hook(info);
+ }
+ });
+ panic::set_hook(hook);
+ }
match console::run_tests_console(&opts, tests) {
Ok(true) => {}
Ok(false) => process::exit(ERROR_EXIT_CODE),
}
}
+struct FilteredTests {
+ tests: Vec<(TestId, TestDescAndFn)>,
+ benchs: Vec<(TestId, TestDescAndFn)>,
+ next_id: usize,
+}
+
+impl FilteredTests {
+ fn add_bench(&mut self, desc: TestDesc, testfn: TestFn) {
+ let test = TestDescAndFn { desc, testfn };
+ self.benchs.push((TestId(self.next_id), test));
+ self.next_id += 1;
+ }
+ fn add_test(&mut self, desc: TestDesc, testfn: TestFn) {
+ let test = TestDescAndFn { desc, testfn };
+ self.tests.push((TestId(self.next_id), test));
+ self.next_id += 1;
+ }
+ fn add_bench_as_test(
+ &mut self,
+ desc: TestDesc,
+ benchfn: impl Fn(&mut Bencher) -> Result<(), String> + Send + 'static,
+ ) {
+ let testfn = DynTestFn(Box::new(move || {
+ bench::run_once(|b| __rust_begin_short_backtrace(|| benchfn(b)))
+ }));
+ self.add_test(desc, testfn);
+ }
+ fn total_len(&self) -> usize {
+ self.tests.len() + self.benchs.len()
+ }
+}
+
pub fn run_tests<F>(
opts: &TestOpts,
tests: Vec<TestDescAndFn>,
join_handle: Option<thread::JoinHandle<()>>,
}
+ impl RunningTest {
+ fn join(self, completed_test: &mut CompletedTest) {
+ if let Some(join_handle) = self.join_handle {
+ if let Err(_) = join_handle.join() {
+ if let TrOk = completed_test.result {
+ completed_test.result =
+ TrFailedMsg("panicked after reporting success".to_string());
+ }
+ }
+ }
+ }
+ }
+
// Use a deterministic hasher
type TestMap =
HashMap<TestId, RunningTest, BuildHasherDefault<collections::hash_map::DefaultHasher>>;
let tests_len = tests.len();
- let mut filtered_tests = filter_tests(opts, tests);
- if !opts.bench_benchmarks {
- filtered_tests = convert_benchmarks_to_tests(filtered_tests);
- }
+ let mut filtered = FilteredTests { tests: Vec::new(), benchs: Vec::new(), next_id: 0 };
- let filtered_tests = {
- let mut filtered_tests = filtered_tests;
- for test in filtered_tests.iter_mut() {
- test.desc.name = test.desc.name.with_padding(test.testfn.padding());
- }
+ for test in filter_tests(opts, tests) {
+ let mut desc = test.desc;
+ desc.name = desc.name.with_padding(test.testfn.padding());
- filtered_tests
- };
+ match test.testfn {
+ DynBenchFn(benchfn) => {
+ if opts.bench_benchmarks {
+ filtered.add_bench(desc, DynBenchFn(benchfn));
+ } else {
+ filtered.add_bench_as_test(desc, benchfn);
+ }
+ }
+ StaticBenchFn(benchfn) => {
+ if opts.bench_benchmarks {
+ filtered.add_bench(desc, StaticBenchFn(benchfn));
+ } else {
+ filtered.add_bench_as_test(desc, benchfn);
+ }
+ }
+ testfn => {
+ filtered.add_test(desc, testfn);
+ }
+ };
+ }
- let filtered_out = tests_len - filtered_tests.len();
+ let filtered_out = tests_len - filtered.total_len();
let event = TestEvent::TeFilteredOut(filtered_out);
notify_about_test_event(event)?;
- let filtered_descs = filtered_tests.iter().map(|t| t.desc.clone()).collect();
-
let shuffle_seed = get_shuffle_seed(opts);
- let event = TestEvent::TeFiltered(filtered_descs, shuffle_seed);
+ let event = TestEvent::TeFiltered(filtered.total_len(), shuffle_seed);
notify_about_test_event(event)?;
- let (mut filtered_tests, filtered_benchs): (Vec<_>, _) = filtered_tests
- .into_iter()
- .enumerate()
- .map(|(i, e)| (TestId(i), e))
- .partition(|(_, e)| matches!(e.testfn, StaticTestFn(_) | DynTestFn(_)));
-
let concurrency = opts.test_threads.unwrap_or_else(get_concurrency);
+ let mut remaining = filtered.tests;
if let Some(shuffle_seed) = shuffle_seed {
- shuffle_tests(shuffle_seed, &mut filtered_tests);
+ shuffle_tests(shuffle_seed, &mut remaining);
}
// Store the tests in a VecDeque so we can efficiently remove the first element to run the
// tests in the order they were passed (unless shuffled).
- let mut remaining = VecDeque::from(filtered_tests);
+ let mut remaining = VecDeque::from(remaining);
let mut pending = 0;
let (tx, rx) = channel::<CompletedTest>();
let (id, test) = remaining.pop_front().unwrap();
let event = TestEvent::TeWait(test.desc.clone());
notify_about_test_event(event)?;
- let join_handle =
- run_test(opts, !opts.run_tests, id, test, run_strategy, tx.clone(), Concurrent::No);
- assert!(join_handle.is_none());
- let completed_test = rx.recv().unwrap();
+ let join_handle = run_test(opts, !opts.run_tests, id, test, run_strategy, tx.clone());
+ // Wait for the test to complete.
+ let mut completed_test = rx.recv().unwrap();
+ RunningTest { join_handle }.join(&mut completed_test);
let event = TestEvent::TeResult(completed_test);
notify_about_test_event(event)?;
let event = TestEvent::TeWait(desc.clone());
notify_about_test_event(event)?; //here no pad
- let join_handle = run_test(
- opts,
- !opts.run_tests,
- id,
- test,
- run_strategy,
- tx.clone(),
- Concurrent::Yes,
- );
+ let join_handle =
+ run_test(opts, !opts.run_tests, id, test, run_strategy, tx.clone());
running_tests.insert(id, RunningTest { join_handle });
timeout_queue.push_back(TimeoutEntry { id, desc, timeout });
pending += 1;
let mut completed_test = res.unwrap();
let running_test = running_tests.remove(&completed_test.id).unwrap();
- if let Some(join_handle) = running_test.join_handle {
- if let Err(_) = join_handle.join() {
- if let TrOk = completed_test.result {
- completed_test.result =
- TrFailedMsg("panicked after reporting success".to_string());
- }
- }
- }
+ running_test.join(&mut completed_test);
let event = TestEvent::TeResult(completed_test);
notify_about_test_event(event)?;
if opts.bench_benchmarks {
// All benchmarks run at the end, in serial.
- for (id, b) in filtered_benchs {
+ for (id, b) in filtered.benchs {
let event = TestEvent::TeWait(b.desc.clone());
notify_about_test_event(event)?;
- run_test(opts, false, id, b, run_strategy, tx.clone(), Concurrent::No);
- let completed_test = rx.recv().unwrap();
+ let join_handle = run_test(opts, false, id, b, run_strategy, tx.clone());
+ // Wait for the test to complete.
+ let mut completed_test = rx.recv().unwrap();
+ RunningTest { join_handle }.join(&mut completed_test);
let event = TestEvent::TeResult(completed_test);
notify_about_test_event(event)?;
}
// Skip tests that match any of the skip filters
- filtered.retain(|test| !opts.skip.iter().any(|sf| matches_filter(test, sf)));
+ if !opts.skip.is_empty() {
+ filtered.retain(|test| !opts.skip.iter().any(|sf| matches_filter(test, sf)));
+ }
// Excludes #[should_panic] tests
if opts.exclude_should_panic {
test: TestDescAndFn,
strategy: RunStrategy,
monitor_ch: Sender<CompletedTest>,
- concurrency: Concurrent,
) -> Option<thread::JoinHandle<()>> {
let TestDescAndFn { desc, testfn } = test;
struct TestRunOpts {
pub strategy: RunStrategy,
pub nocapture: bool,
- pub concurrency: Concurrent,
pub time: Option<time::TestTimeOptions>,
}
testfn: Box<dyn FnOnce() -> Result<(), String> + Send>,
opts: TestRunOpts,
) -> Option<thread::JoinHandle<()>> {
- let concurrency = opts.concurrency;
let name = desc.name.clone();
let runtest = move || match opts.strategy {
// the test synchronously, regardless of the concurrency
// level.
let supports_threads = !cfg!(target_os = "emscripten") && !cfg!(target_family = "wasm");
- if concurrency == Concurrent::Yes && supports_threads {
+ if supports_threads {
let cfg = thread::Builder::new().name(name.as_slice().to_owned());
let mut runtest = Arc::new(Mutex::new(Some(runtest)));
let runtest2 = runtest.clone();
}
let test_run_opts =
- TestRunOpts { strategy, nocapture: opts.nocapture, concurrency, time: opts.time_options };
+ TestRunOpts { strategy, nocapture: opts.nocapture, time: opts.time_options };
match testfn {
DynBenchFn(benchfn) => {
//! Enums denoting options for test execution.
-/// Whether to execute tests concurrently or not
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum Concurrent {
- Yes,
- No,
-}
-
/// Number of times to run a benchmarked function
#[derive(Clone, PartialEq, Eq)]
pub enum BenchMode {
testfn: DynTestFn(Box::new(f)),
};
let (tx, rx) = channel();
- run_test(&TestOpts::new(), false, TestId(0), desc, RunStrategy::InProcess, tx, Concurrent::No);
+ run_test(&TestOpts::new(), false, TestId(0), desc, RunStrategy::InProcess, tx);
let result = rx.recv().unwrap().result;
assert_ne!(result, TrOk);
}
testfn: DynTestFn(Box::new(f)),
};
let (tx, rx) = channel();
- run_test(&TestOpts::new(), false, TestId(0), desc, RunStrategy::InProcess, tx, Concurrent::No);
+ run_test(&TestOpts::new(), false, TestId(0), desc, RunStrategy::InProcess, tx);
let result = rx.recv().unwrap().result;
assert_eq!(result, TrIgnored);
}
testfn: DynTestFn(Box::new(f)),
};
let (tx, rx) = channel();
- run_test(&TestOpts::new(), false, TestId(0), desc, RunStrategy::InProcess, tx, Concurrent::No);
+ run_test(&TestOpts::new(), false, TestId(0), desc, RunStrategy::InProcess, tx);
let result = rx.recv().unwrap().result;
assert_eq!(result, TrOk);
}
testfn: DynTestFn(Box::new(f)),
};
let (tx, rx) = channel();
- run_test(&TestOpts::new(), false, TestId(0), desc, RunStrategy::InProcess, tx, Concurrent::No);
+ run_test(&TestOpts::new(), false, TestId(0), desc, RunStrategy::InProcess, tx);
let result = rx.recv().unwrap().result;
assert_eq!(result, TrOk);
}
testfn: DynTestFn(Box::new(f)),
};
let (tx, rx) = channel();
- run_test(&TestOpts::new(), false, TestId(0), desc, RunStrategy::InProcess, tx, Concurrent::No);
+ run_test(&TestOpts::new(), false, TestId(0), desc, RunStrategy::InProcess, tx);
let result = rx.recv().unwrap().result;
assert_eq!(result, TrFailedMsg(failed_msg.to_string()));
}
testfn: DynTestFn(Box::new(f)),
};
let (tx, rx) = channel();
- run_test(&TestOpts::new(), false, TestId(0), desc, RunStrategy::InProcess, tx, Concurrent::No);
+ run_test(&TestOpts::new(), false, TestId(0), desc, RunStrategy::InProcess, tx);
let result = rx.recv().unwrap().result;
assert_eq!(result, TrFailedMsg(failed_msg));
}
testfn: DynTestFn(Box::new(f)),
};
let (tx, rx) = channel();
- run_test(
- &TestOpts::new(),
- false,
- TestId(0),
- desc,
- RunStrategy::InProcess,
- tx,
- Concurrent::No,
- );
+ run_test(&TestOpts::new(), false, TestId(0), desc, RunStrategy::InProcess, tx);
let result = rx.recv().unwrap().result;
assert_eq!(
result,
let test_opts = TestOpts { time_options, ..TestOpts::new() };
let (tx, rx) = channel();
- run_test(&test_opts, false, TestId(0), desc, RunStrategy::InProcess, tx, Concurrent::No);
+ run_test(&test_opts, false, TestId(0), desc, RunStrategy::InProcess, tx);
let exec_time = rx.recv().unwrap().exec_time;
exec_time
}
let test_opts = TestOpts { time_options: Some(time_options), ..TestOpts::new() };
let (tx, rx) = channel();
- run_test(&test_opts, false, TestId(0), desc, RunStrategy::InProcess, tx, Concurrent::No);
+ run_test(&test_opts, false, TestId(0), desc, RunStrategy::InProcess, tx);
let result = rx.recv().unwrap().result;
result
core = { path = "../core" }
libc = { version = "0.2.79", features = ['rustc-dep-of-std'], default-features = false }
compiler_builtins = "0.1.0"
-cfg-if = "0.1.8"
+cfg-if = "1.0"
[build-dependencies]
cc = "1.0.69"
[[package]]
name = "fd-lock"
-version = "3.0.6"
+version = "3.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e11dcc7e4d79a8c89b9ab4c6f5c30b1fc4a83c420792da3542fd31179ed5f517"
+checksum = "0c93a581058d957dc4176875aad04f82f81613e6611d64aa1a9c755bdfb16711"
dependencies = [
"cfg-if",
"rustix",
- "windows-sys",
+ "windows-sys 0.42.0",
]
[[package]]
"io-lifetimes",
"libc",
"linux-raw-sys",
- "windows-sys",
+ "windows-sys 0.36.1",
]
[[package]]
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
dependencies = [
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_msvc",
+ "windows_aarch64_msvc 0.36.1",
+ "windows_i686_gnu 0.36.1",
+ "windows_i686_msvc 0.36.1",
+ "windows_x86_64_gnu 0.36.1",
+ "windows_x86_64_msvc 0.36.1",
]
+[[package]]
+name = "windows-sys"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc 0.42.0",
+ "windows_i686_gnu 0.42.0",
+ "windows_i686_msvc 0.42.0",
+ "windows_x86_64_gnu 0.42.0",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc 0.42.0",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
+
[[package]]
name = "windows_aarch64_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
+
[[package]]
name = "windows_i686_gnu"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
+[[package]]
+name = "windows_i686_gnu"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
+
[[package]]
name = "windows_i686_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
+[[package]]
+name = "windows_i686_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
+
[[package]]
name = "windows_x86_64_gnu"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
+
[[package]]
name = "windows_x86_64_msvc"
version = "0.36.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
+
[[package]]
name = "xattr"
version = "0.2.3"
[dependencies]
cmake = "0.1.38"
-fd-lock = "3.0.6"
+fd-lock = "3.0.7"
filetime = "0.2"
getopts = "0.2.19"
cc = "1.0.69"
// NOTE: Since `./configure` generates a `config.toml`, distro maintainers will see the
// changelog warning, not the `x.py setup` message.
- let suggest_setup = !config.config.exists() && !matches!(config.cmd, Subcommand::Setup { .. });
+ let suggest_setup = config.config.is_none() && !matches!(config.cmd, Subcommand::Setup { .. });
if suggest_setup {
println!("warning: you have not made a `config.toml`");
println!(
arg.push(&linker);
cmd.arg(arg);
}
- if env::var_os("RUSTDOC_FUSE_LD_LLD").is_some() {
+ if let Ok(no_threads) = env::var("RUSTDOC_LLD_NO_THREADS") {
cmd.arg("-Clink-arg=-fuse-ld=lld");
- if cfg!(windows) {
- cmd.arg("-Clink-arg=-Wl,/threads:1");
- } else {
- cmd.arg("-Clink-arg=-Wl,--threads=1");
- }
+ cmd.arg(format!("-Clink-arg=-Wl,{}", no_threads));
}
// Cargo doesn't pass RUSTDOCFLAGS to proc_macros:
// https://github.com/rust-lang/cargo/issues/4423
check::CodegenBackend,
check::Clippy,
check::Miri,
+ check::CargoMiri,
+ check::MiroptTestTools,
check::Rls,
check::RustAnalyzer,
check::Rustfmt,
false
}
+
+ pub(crate) fn maybe_open_in_browser<S: Step>(&self, path: impl AsRef<Path>) {
+ if self.was_invoked_explicitly::<S>(Kind::Doc) {
+ self.open_in_browser(path);
+ }
+ }
+
+ pub(crate) fn open_in_browser(&self, path: impl AsRef<Path>) {
+ if self.config.dry_run || !self.config.cmd.open() {
+ return;
+ }
+
+ let path = path.as_ref();
+ self.info(&format!("Opening doc {}", path.display()));
+ if let Err(err) = opener::open(path) {
+ self.info(&format!("{}\n", err));
+ }
+ }
}
#[cfg(test)]
}
tool_check_step!(Rustdoc, "src/tools/rustdoc", "src/librustdoc", SourceType::InTree);
-// Clippy and Rustfmt are hybrids. They are external tools, but use a git subtree instead
+// Clippy, miri and Rustfmt are hybrids. They are external tools, but use a git subtree instead
// of a submodule. Since the SourceType only drives the deny-warnings
// behavior, treat it as in-tree so that any new warnings in clippy will be
// rejected.
tool_check_step!(Clippy, "src/tools/clippy", SourceType::InTree);
-// Miri on the other hand is treated as out of tree, since InTree also causes it to
-// be run as part of `check`, which can fail on platforms which libffi-sys has no support for.
-tool_check_step!(Miri, "src/tools/miri", SourceType::Submodule);
+tool_check_step!(Miri, "src/tools/miri", SourceType::InTree);
+tool_check_step!(CargoMiri, "src/tools/miri/cargo-miri", SourceType::InTree);
tool_check_step!(Rls, "src/tools/rls", SourceType::InTree);
tool_check_step!(Rustfmt, "src/tools/rustfmt", SourceType::InTree);
+tool_check_step!(MiroptTestTools, "src/tools/miropt-test-tools", SourceType::InTree);
tool_check_step!(Bootstrap, "src/bootstrap", SourceType::InTree, false);
// Determine if we're going to compile in optimized C intrinsics to
// the `compiler-builtins` crate. These intrinsics live in LLVM's
- // `compiler-rt` repository.
+ // `compiler-rt` repository, but our `src/llvm-project` submodule isn't
+ // always checked out, so we need to conditionally look for this. (e.g. if
+ // an external LLVM is used we skip the LLVM submodule checkout).
//
// Note that this shouldn't affect the correctness of `compiler-builtins`,
// but only its speed. Some intrinsics in C haven't been translated to Rust
// If `compiler-rt` is available ensure that the `c` feature of the
// `compiler-builtins` crate is enabled and it's configured to learn where
// `compiler-rt` is located.
- let compiler_builtins_c_feature = if builder.config.optimized_compiler_builtins {
- if !builder.is_rust_llvm(target) {
- panic!(
- "need a managed LLVM submodule for optimized intrinsics support; unset `llvm-config` or `optimized-compiler-builtins`"
- );
- }
-
- builder.update_submodule(&Path::new("src").join("llvm-project"));
- let compiler_builtins_root = builder.src.join("src/llvm-project/compiler-rt");
+ let compiler_builtins_root = builder.src.join("src/llvm-project/compiler-rt");
+ let compiler_builtins_c_feature = if compiler_builtins_root.exists() {
// Note that `libprofiler_builtins/build.rs` also computes this so if
// you're changing something here please also change that.
cargo.env("RUST_COMPILER_RT_ROOT", &compiler_builtins_root);
pub color: Color,
pub patch_binaries_for_nix: bool,
pub stage0_metadata: Stage0Metadata,
- /// Whether to use the `c` feature of the `compiler_builtins` crate.
- pub optimized_compiler_builtins: bool,
pub on_fail: Option<String>,
pub stage: u32,
pub keep_stage_std: Vec<u32>,
pub src: PathBuf,
/// defaults to `config.toml`
- pub config: PathBuf,
+ pub config: Option<PathBuf>,
pub jobs: Option<u32>,
pub cmd: Subcommand,
pub incremental: bool,
bench_stage: Option<u32> = "bench-stage",
patch_binaries_for_nix: Option<bool> = "patch-binaries-for-nix",
metrics: Option<bool> = "metrics",
- optimized_compiler_builtins: Option<bool> = "optimized-compiler-builtins",
}
}
// Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path,
// but not if `config.toml` hasn't been created.
let mut toml = if !using_default_path || toml_path.exists() {
+ config.config = Some(toml_path.clone());
get_toml(&toml_path)
} else {
+ config.config = None;
TomlConfig::default()
};
}
config.changelog_seen = toml.changelog_seen;
- config.config = toml_path;
let build = toml.build.unwrap_or_default();
set(&mut config.print_step_timings, build.print_step_timings);
set(&mut config.print_step_rusage, build.print_step_rusage);
set(&mut config.patch_binaries_for_nix, build.patch_binaries_for_nix);
- set(&mut config.optimized_compiler_builtins, build.optimized_compiler_builtins);
config.verbose = cmp::max(config.verbose, flags.verbose);
git
}
- pub(crate) fn artifact_channel(&self, builder: &Builder<'_>, commit: &str) -> String {
- if builder.rust_info.is_managed_git_subrepository() {
+ /// 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, builder: &Builder<'_>, commit: &str) -> String {
+ let (channel, version) = if builder.rust_info.is_managed_git_subrepository() {
let mut channel = self.git();
channel.arg("show").arg(format!("{}:src/ci/channel", commit));
let channel = output(&mut channel);
- channel.trim().to_owned()
- } else if let Ok(channel) = fs::read_to_string(builder.src.join("src/ci/channel")) {
- channel.trim().to_owned()
+ let mut version = self.git();
+ version.arg("show").arg(format!("{}:src/version", commit));
+ let version = output(&mut version);
+ (channel.trim().to_owned(), version.trim().to_owned())
} else {
- let src = builder.src.display();
- eprintln!("error: failed to determine artifact channel");
- eprintln!(
- "help: either use git or ensure that {src}/src/ci/channel contains the name of the channel to use"
- );
- panic!();
+ let channel = fs::read_to_string(builder.src.join("src/ci/channel"));
+ let version = fs::read_to_string(builder.src.join("src/version"));
+ match (channel, version) {
+ (Ok(channel), Ok(version)) => {
+ (channel.trim().to_owned(), version.trim().to_owned())
+ }
+ (channel, version) => {
+ let src = builder.src.display();
+ eprintln!("error: failed to determine artifact channel and/or version");
+ eprintln!(
+ "help: consider using a git checkout or ensure these files are readable"
+ );
+ if let Err(channel) = channel {
+ eprintln!("reading {}/src/ci/channel failed: {:?}", src, channel);
+ }
+ if let Err(version) = version {
+ eprintln!("reading {}/src/version failed: {:?}", src, version);
+ }
+ panic!();
+ }
+ }
+ };
+
+ match channel.as_str() {
+ "stable" => version,
+ "beta" => channel,
+ "nightly" => channel,
+ other => unreachable!("{:?} is not recognized as a valid channel", other),
}
}
fn download_ci_rustc(builder: &Builder<'_>, commit: &str) {
builder.verbose(&format!("using downloaded stage2 artifacts from CI (commit {commit})"));
- let channel = builder.config.artifact_channel(builder, commit);
+ let version = builder.config.artifact_version_part(builder, commit);
let host = builder.config.build.triple;
let bin_root = builder.out.join(host).join("ci-rustc");
let rustc_stamp = bin_root.join(".rustc-stamp");
if bin_root.exists() {
t!(fs::remove_dir_all(&bin_root));
}
- let filename = format!("rust-std-{channel}-{host}.tar.xz");
+ let filename = format!("rust-std-{version}-{host}.tar.xz");
let pattern = format!("rust-std-{host}");
download_ci_component(builder, filename, &pattern, commit);
- let filename = format!("rustc-{channel}-{host}.tar.xz");
+ let filename = format!("rustc-{version}-{host}.tar.xz");
download_ci_component(builder, filename, "rustc", commit);
// download-rustc doesn't need its own cargo, it can just use beta's.
- let filename = format!("rustc-dev-{channel}-{host}.tar.xz");
+ let filename = format!("rustc-dev-{version}-{host}.tar.xz");
download_ci_component(builder, filename, "rustc-dev", commit);
builder.fix_bin_or_dylib(&bin_root.join("bin").join("rustc"));
use crate::channel;
use crate::compile;
use crate::config::TargetSelection;
+use crate::doc::DocumentationFormat;
use crate::tarball::{GeneratedTarball, OverlayKind, Tarball};
use crate::tool::{self, Tool};
use crate::util::{exe, is_dylib, output, t, timeit};
/// Builds the `rust-docs-json` installer component.
fn run(self, builder: &Builder<'_>) -> Option<GeneratedTarball> {
let host = self.host;
- builder.ensure(crate::doc::JsonStd { stage: builder.top_stage, target: host });
+ builder.ensure(crate::doc::Std {
+ stage: builder.top_stage,
+ target: host,
+ format: DocumentationFormat::JSON,
+ });
let dest = "share/doc/rust/json";
///
/// Returns whether the files were actually copied.
fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir: &Path) -> bool {
- if !builder.is_rust_llvm(target) {
- // If the LLVM was externally provided, then we don't currently copy
- // artifacts into the sysroot. This is not necessarily the right
- // choice (in particular, it will require the LLVM dylib to be in
- // the linker's load path at runtime), but the common use case for
- // external LLVMs is distribution provided LLVMs, and in that case
- // they're usually in the standard search path (e.g., /usr/lib) and
- // copying them here is going to cause problems as we may end up
- // with the wrong files and isn't what distributions want.
- //
- // This behavior may be revisited in the future though.
- //
- // If the LLVM is coming from ourselves (just from CI) though, we
- // still want to install it, as it otherwise won't be available.
- return false;
+ if let Some(config) = builder.config.target_config.get(&target) {
+ if config.llvm_config.is_some() && !builder.config.llvm_from_ci {
+ // If the LLVM was externally provided, then we don't currently copy
+ // artifacts into the sysroot. This is not necessarily the right
+ // choice (in particular, it will require the LLVM dylib to be in
+ // the linker's load path at runtime), but the common use case for
+ // external LLVMs is distribution provided LLVMs, and in that case
+ // they're usually in the standard search path (e.g., /usr/lib) and
+ // copying them here is going to cause problems as we may end up
+ // with the wrong files and isn't what distributions want.
+ //
+ // This behavior may be revisited in the future though.
+ //
+ // If the LLVM is coming from ourselves (just from CI) though, we
+ // still want to install it, as it otherwise won't be available.
+ return false;
+ }
}
// On macOS, rustc (and LLVM tools) link to an unversioned libLLVM.dylib
StyleGuide, "src/doc/style-guide", "style-guide";
);
-fn open(builder: &Builder<'_>, path: impl AsRef<Path>) {
- if builder.config.dry_run || !builder.config.cmd.open() {
- return;
- }
-
- let path = path.as_ref();
- builder.info(&format!("Opening doc {}", path.display()));
- if let Err(err) = opener::open(path) {
- builder.info(&format!("{}\n", err));
- }
-}
-
// "library/std" -> ["library", "std"]
//
// Used for deciding whether a particular step is one requested by the user on
invoke_rustdoc(builder, compiler, &shared_assets, target, path);
}
- if builder.was_invoked_explicitly::<Self>(Kind::Doc) {
- let out = builder.doc_out(target);
- let index = out.join("book").join("index.html");
- open(builder, &index);
- }
+ let out = builder.doc_out(target);
+ let index = out.join("book").join("index.html");
+ builder.maybe_open_in_browser::<Self>(index);
}
}
// with no particular explicit doc requested (e.g. library/core).
if builder.paths.is_empty() || builder.was_invoked_explicitly::<Self>(Kind::Doc) {
let index = out.join("index.html");
- open(builder, &index);
+ builder.open_in_browser(&index);
}
}
}
pub struct Std {
pub stage: u32,
pub target: TargetSelection,
+ pub format: DocumentationFormat,
}
impl Step for Std {
}
fn make_run(run: RunConfig<'_>) {
- run.builder.ensure(Std { stage: run.builder.top_stage, target: run.target });
+ run.builder.ensure(Std {
+ stage: run.builder.top_stage,
+ target: run.target,
+ format: if run.builder.config.cmd.json() {
+ DocumentationFormat::JSON
+ } else {
+ DocumentationFormat::HTML
+ },
+ });
}
/// Compile all standard library documentation.
fn run(self, builder: &Builder<'_>) {
let stage = self.stage;
let target = self.target;
- let out = builder.doc_out(target);
+ let out = match self.format {
+ DocumentationFormat::HTML => builder.doc_out(target),
+ DocumentationFormat::JSON => builder.json_doc_out(target),
+ };
+
t!(fs::create_dir_all(&out));
builder.ensure(SharedAssets { target: self.target });
let index_page = builder.src.join("src/doc/index.md").into_os_string();
- let mut extra_args = vec![
- OsStr::new("--markdown-css"),
- OsStr::new("rust.css"),
- OsStr::new("--markdown-no-toc"),
- OsStr::new("--index-page"),
- &index_page,
- ];
+ let mut extra_args = match self.format {
+ DocumentationFormat::HTML => vec![
+ OsStr::new("--markdown-css"),
+ OsStr::new("rust.css"),
+ OsStr::new("--markdown-no-toc"),
+ OsStr::new("--index-page"),
+ &index_page,
+ ],
+ DocumentationFormat::JSON => vec![OsStr::new("--output-format"), OsStr::new("json")],
+ };
if !builder.config.docs_minification {
extra_args.push(OsStr::new("--disable-minification"));
})
.collect::<Vec<_>>();
- doc_std(
- builder,
- DocumentationFormat::HTML,
- stage,
- target,
- &out,
- &extra_args,
- &requested_crates,
- );
+ doc_std(builder, self.format, stage, target, &out, &extra_args, &requested_crates);
+
+ // Don't open if the format is json
+ if let DocumentationFormat::JSON = self.format {
+ return;
+ }
// Look for library/std, library/core etc in the `x.py doc` arguments and
// open the corresponding rendered docs.
for requested_crate in requested_crates {
if STD_PUBLIC_CRATES.iter().any(|k| *k == requested_crate.as_str()) {
let index = out.join(requested_crate).join("index.html");
- open(builder, &index);
+ builder.open_in_browser(index);
}
}
}
}
-#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
-pub struct JsonStd {
- pub stage: u32,
- pub target: TargetSelection,
-}
-
-impl Step for JsonStd {
- type Output = ();
- const DEFAULT: bool = false;
-
- fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
- let default = run.builder.config.docs && run.builder.config.cmd.json();
- run.all_krates("test").path("library").default_condition(default)
- }
-
- fn make_run(run: RunConfig<'_>) {
- run.builder.ensure(Std { stage: run.builder.top_stage, target: run.target });
- }
-
- /// Build JSON documentation for the standard library crates.
- ///
- /// This is largely just a wrapper around `cargo doc`.
- fn run(self, builder: &Builder<'_>) {
- let stage = self.stage;
- let target = self.target;
- let out = builder.json_doc_out(target);
- t!(fs::create_dir_all(&out));
- let extra_args = [OsStr::new("--output-format"), OsStr::new("json")];
- doc_std(builder, DocumentationFormat::JSON, stage, target, &out, &extra_args, &[])
- }
-}
-
/// Name of the crates that are visible to consumers of the standard library.
/// Documentation for internal crates is handled by the rustc step, so internal crates will show
/// up there.
const STD_PUBLIC_CRATES: [&str; 5] = ["core", "alloc", "std", "proc_macro", "test"];
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
-enum DocumentationFormat {
+pub enum DocumentationFormat {
HTML,
JSON,
}
// Let's open the first crate documentation page:
if let Some(krate) = to_open {
let index = out.join(krate).join("index.html");
- open(builder, &index);
+ builder.open_in_browser(index);
}
}
}
macro_rules! tool_doc {
- ($tool: ident, $should_run: literal, $path: literal, [$($krate: literal),+ $(,)?], in_tree = $in_tree:expr $(,)?) => {
+ ($tool: ident, $should_run: literal, $path: literal, [$($krate: literal),+ $(,)?] $(,)?) => {
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct $tool {
target: TargetSelection,
t!(fs::create_dir_all(&out_dir));
t!(symlink_dir_force(&builder.config, &out, &out_dir));
- let source_type = if $in_tree == true {
- SourceType::InTree
- } else {
- SourceType::Submodule
- };
-
// Build cargo command.
let mut cargo = prepare_tool_cargo(
builder,
target,
"doc",
$path,
- source_type,
+ SourceType::InTree,
&[],
);
cargo.rustdocflag("--show-type-layout");
cargo.rustdocflag("--generate-link-to-definition");
cargo.rustdocflag("-Zunstable-options");
- if $in_tree == true {
- builder.run(&mut cargo.into());
- } else {
- // Allow out-of-tree docs to fail (since the tool might be in a broken state).
- if !builder.try_run(&mut cargo.into()) {
- builder.info(&format!(
- "WARNING: tool {} failed to document; ignoring failure because it is an out-of-tree tool",
- stringify!($tool).to_lowercase(),
- ));
- }
- }
+ builder.run(&mut cargo.into());
}
}
}
}
-tool_doc!(
- Rustdoc,
- "rustdoc-tool",
- "src/tools/rustdoc",
- ["rustdoc", "rustdoc-json-types"],
- in_tree = true
-);
+tool_doc!(Rustdoc, "rustdoc-tool", "src/tools/rustdoc", ["rustdoc", "rustdoc-json-types"],);
tool_doc!(
Rustfmt,
"rustfmt-nightly",
"src/tools/rustfmt",
["rustfmt-nightly", "rustfmt-config_proc_macro"],
- in_tree = true
);
-tool_doc!(Clippy, "clippy", "src/tools/clippy", ["clippy_utils"], in_tree = true);
-tool_doc!(Miri, "miri", "src/tools/miri", ["miri"], in_tree = false);
+tool_doc!(Clippy, "clippy", "src/tools/clippy", ["clippy_utils"]);
+tool_doc!(Miri, "miri", "src/tools/miri", ["miri"]);
#[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct ErrorIndex {
name: INTERNER.intern_str("rustc"),
src: INTERNER.intern_path(out_base),
});
- if builder.was_invoked_explicitly::<Self>(Kind::Doc) {
- let out = builder.doc_out(self.target);
- let index = out.join("rustc").join("index.html");
- open(builder, &index);
- }
+
+ let out = builder.doc_out(self.target);
+ let index = out.join("rustc").join("index.html");
+ builder.maybe_open_in_browser::<Self>(index);
}
}
options[0] = Some("-Clink-arg=-fuse-ld=lld".to_string());
}
- let threads = if target.contains("windows") { "/threads:1" } else { "--threads=1" };
- options[1] = Some(format!("-Clink-arg=-Wl,{}", threads));
+ let no_threads = util::lld_flag_no_threads(target.contains("windows"));
+ options[1] = Some(format!("-Clink-arg=-Wl,{}", no_threads));
}
IntoIterator::into_iter(options).flatten()
} else {
&builder.config.stage0_metadata.config.artifacts_server
};
- let channel = builder.config.artifact_channel(builder, llvm_sha);
- let filename = format!("rust-dev-{}-{}.tar.xz", channel, builder.build.build.triple);
+ let version = builder.config.artifact_version_part(builder, llvm_sha);
+ let filename = format!("rust-dev-{}-{}.tar.xz", version, builder.build.build.triple);
let tarball = rustc_cache.join(&filename);
if !tarball.exists() {
let help_on_error = "error: failed to download llvm from ci
continue;
}
+ // Some environments don't want or need these tools, such as when testing Miri.
+ // FIXME: it would be better to refactor this code to split necessary setup from pure sanity
+ // checks, and have a regular flag for skipping the latter. Also see
+ // <https://github.com/rust-lang/rust/pull/103569#discussion_r1008741742>.
+ if env::var_os("BOOTSTRAP_SKIP_TARGET_SANITY").is_some() {
+ continue;
+ }
+
if !build.config.dry_run {
cmd_finder.must_have(build.cc(*target));
if let Some(ar) = build.ar(*target) {
}
}
+ // Some environments don't want or need these tools, such as when testing Miri.
+ // FIXME: it would be better to refactor this code to split necessary setup from pure sanity
+ // checks, and have a regular flag for skipping the latter. Also see
+ // <https://github.com/rust-lang/rust/pull/103569#discussion_r1008741742>.
+ if env::var_os("BOOTSTRAP_SKIP_TARGET_SANITY").is_some() {
+ continue;
+ }
+
if need_cmake && target.contains("msvc") {
// There are three builds of cmake on windows: MSVC, MinGW, and
// Cygwin. The Cygwin build does not have generators for Visual
}
pub fn setup(config: &Config, profile: Profile) {
- let path = &config.config;
+ let path = &config.config.clone().unwrap_or(PathBuf::from("config.toml"));
if path.exists() {
eprintln!(
use crate::compile;
use crate::config::TargetSelection;
use crate::dist;
+use crate::doc::DocumentationFormat;
use crate::flags::Subcommand;
use crate::native;
use crate::tool::{self, SourceType, Tool};
host,
"run",
"src/tools/miri/cargo-miri",
- SourceType::Submodule,
+ SourceType::InTree,
&[],
);
cargo.add_rustc_lib_path(builder, compiler);
host,
"test",
"src/tools/miri",
- SourceType::Submodule,
+ SourceType::InTree,
&[],
);
cargo.add_rustc_lib_path(builder, compiler);
cmd.env("RUSTDOC_LINKER", linker);
}
if builder.is_fuse_ld_lld(self.compiler.host) {
- cmd.env("RUSTDOC_FUSE_LD_LLD", "1");
+ cmd.env(
+ "RUSTDOC_LLD_NO_THREADS",
+ util::lld_flag_no_threads(self.compiler.host.contains("windows")),
+ );
}
try_run(builder, &mut cmd);
}
command.arg("--test-file").arg(path);
}
}
- builder.ensure(crate::doc::Std { target: self.target, stage: builder.top_stage });
+ builder.ensure(crate::doc::Std {
+ target: self.target,
+ stage: builder.top_stage,
+ format: DocumentationFormat::HTML,
+ });
builder.run(&mut command);
} else {
builder.info("No nodejs found, skipping \"src/test/rustdoc-js-std\" tests");
.arg("doc")
.arg("--target-dir")
.arg(&out_dir)
+ .env("RUSTC_BOOTSTRAP", "1")
.env("RUSTDOC", builder.rustdoc(self.compiler))
.env("RUSTC", builder.rustc(self.compiler))
.current_dir(path);
if builder.is_verbose() {
cmd.arg("--verbose");
}
+ if builder.config.cmd.bless() {
+ cmd.arg("--bless");
+ }
builder.info("tidy check");
try_run(builder, &mut cmd);
}
let mut flags = if is_rustdoc { Vec::new() } else { vec!["-Crpath".to_string()] };
flags.push(format!("-Cdebuginfo={}", builder.config.rust_debuginfo_level_tests));
- flags.push(builder.config.cmd.rustc_args().join(" "));
+ flags.extend(builder.config.cmd.rustc_args().iter().map(|s| s.to_string()));
if let Some(linker) = builder.linker(target) {
cmd.arg("--linker").arg(linker);
let mut hostflags = flags.clone();
hostflags.push(format!("-Lnative={}", builder.test_helpers_out(compiler.host).display()));
hostflags.extend(builder.lld_flags(compiler.host));
- cmd.arg("--host-rustcflags").arg(hostflags.join(" "));
+ for flag in hostflags {
+ cmd.arg("--host-rustcflags").arg(flag);
+ }
let mut targetflags = flags;
targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display()));
targetflags.extend(builder.lld_flags(target));
- cmd.arg("--target-rustcflags").arg(targetflags.join(" "));
+ for flag in targetflags {
+ cmd.arg("--target-rustcflags").arg(flag);
+ }
cmd.arg("--python").arg(builder.python());
let mut rustbook_cmd = builder.tool_cmd(Tool::Rustbook);
let path = builder.src.join(&self.path);
+ // Books often have feature-gated example text.
+ rustbook_cmd.env("RUSTC_BOOTSTRAP", "1");
rustbook_cmd.env("PATH", new_path).arg("test").arg(path);
builder.add_rust_test_threads(&mut rustbook_cmd);
builder.info(&format!("Testing rustbook {}", self.path.display()));
$($name:ident,
$path:expr,
$tool_name:expr,
- stable = $stable:expr,
- $(in_tree = $in_tree:expr,)?
- $(tool_std = $tool_std:literal,)?
- $extra_deps:block;)+) => {
+ stable = $stable:expr
+ $(,tool_std = $tool_std:literal)?
+ ;)+) => {
$(
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct $name {
#[allow(unused_mut)]
fn run(mut $sel, $builder: &Builder<'_>) -> Option<PathBuf> {
- $extra_deps
$builder.ensure(ToolBuild {
compiler: $sel.compiler,
target: $sel.target,
path: $path,
extra_features: $sel.extra_features,
is_optional_tool: true,
- source_type: if false $(|| $in_tree)* {
- SourceType::InTree
- } else {
- SourceType::Submodule
- },
+ source_type: SourceType::InTree,
})
}
}
// Note: Most submodule updates for tools are handled by bootstrap.py, since they're needed just to
// invoke Cargo to build bootstrap. See the comment there for more details.
tool_extended!((self, builder),
- Cargofmt, "src/tools/rustfmt", "cargo-fmt", stable=true, in_tree=true, {};
- CargoClippy, "src/tools/clippy", "cargo-clippy", stable=true, in_tree=true, {};
- Clippy, "src/tools/clippy", "clippy-driver", stable=true, in_tree=true, {};
- Miri, "src/tools/miri", "miri", stable=false, in_tree=true, {};
- CargoMiri, "src/tools/miri/cargo-miri", "cargo-miri", stable=false, in_tree=true, {};
+ Cargofmt, "src/tools/rustfmt", "cargo-fmt", stable=true;
+ CargoClippy, "src/tools/clippy", "cargo-clippy", stable=true;
+ Clippy, "src/tools/clippy", "clippy-driver", stable=true;
+ Miri, "src/tools/miri", "miri", stable=false;
+ CargoMiri, "src/tools/miri/cargo-miri", "cargo-miri", stable=true;
// FIXME: tool_std is not quite right, we shouldn't allow nightly features.
// But `builder.cargo` doesn't know how to handle ToolBootstrap in stages other than 0,
// and this is close enough for now.
- Rls, "src/tools/rls", "rls", stable=true, in_tree=true, tool_std=true, {};
- RustDemangler, "src/tools/rust-demangler", "rust-demangler", stable=false, in_tree=true, tool_std=true, {};
- Rustfmt, "src/tools/rustfmt", "rustfmt", stable=true, in_tree=true, {};
+ Rls, "src/tools/rls", "rls", stable=true, tool_std=true;
+ RustDemangler, "src/tools/rust-demangler", "rust-demangler", stable=false, tool_std=true;
+ Rustfmt, "src/tools/rustfmt", "rustfmt", stable=true;
);
impl<'a> Builder<'a> {
use crate::builder::Builder;
use crate::config::{Config, TargetSelection};
+use crate::OnceCell;
/// A helper macro to `unwrap` a result except also print out details like:
///
let clang_rt_dir = clang_rt_builtins.parent().expect("The clang lib folder should exist");
clang_rt_dir.to_path_buf()
}
+
+pub fn lld_flag_no_threads(is_windows: bool) -> &'static str {
+ static LLD_NO_THREADS: OnceCell<(&'static str, &'static str)> = OnceCell::new();
+ let (windows, other) = LLD_NO_THREADS.get_or_init(|| {
+ let out = output(Command::new("lld").arg("-flavor").arg("ld").arg("--version"));
+ let newer = match (out.find(char::is_numeric), out.find('.')) {
+ (Some(b), Some(e)) => out.as_str()[b..e].parse::<i32>().ok().unwrap_or(14) > 10,
+ _ => true,
+ };
+ if newer { ("/threads:1", "--threads=1") } else { ("/no-threads", "--no-threads") }
+ });
+ if is_windows { windows } else { other }
+}
--set=$TARGET.cc=x86_64-unknown-haiku-gcc \
--set=$TARGET.cxx=x86_64-unknown-haiku-g++ \
--set=$TARGET.llvm-config=/bin/llvm-config-haiku
-ENV EXTERNAL_LLVM 1
-
ENV SCRIPT python3 ../x.py dist --host=$HOST --target=$HOST
--set target.wasm32-wasi.wasi-root=/wasm32-wasi \
--musl-root-armv7=/musl-armv7
-ENV EXTERNAL_LLVM 1
-
ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS
pkg-config \
xz-utils \
wget \
- patch
+ patch \
+ ovmf \
+ qemu-system-x86
RUN curl -sL https://nodejs.org/dist/v15.14.0/node-v15.14.0-linux-x64.tar.xz | \
tar -xJ
CXX_x86_64_unknown_linux_musl=x86_64-linux-musl-g++
ENV MUSL_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $MUSL_TARGETS
-ENV SCRIPT $WASM_SCRIPT && $NVPTX_SCRIPT && $MUSL_SCRIPT
+COPY host-x86_64/test-various/uefi_qemu_test /uefi_qemu_test
+ENV UEFI_TARGETS=x86_64-unknown-uefi
+ENV UEFI_SCRIPT python3 /checkout/x.py --stage 2 build --host='' --target $UEFI_TARGETS && \
+ python3 -u /uefi_qemu_test/run.py
+
+ENV SCRIPT $WASM_SCRIPT && $NVPTX_SCRIPT && $MUSL_SCRIPT && $UEFI_SCRIPT
--- /dev/null
+[package]
+name = "uefi_qemu_test"
+version = "0.0.0"
+edition = "2021"
+
+[workspace]
+
+[dependencies]
+r-efi = "4.1.0"
--- /dev/null
+#!/usr/bin/env python3
+
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+
+from pathlib import Path
+
+
+def run(*cmd, capture=False, check=True, env=None):
+ """Print and run a command, optionally capturing the output."""
+ cmd = [str(p) for p in cmd]
+ print(' '.join(cmd))
+ return subprocess.run(cmd,
+ capture_output=capture,
+ check=check,
+ env=env,
+ text=True)
+
+
+def build_and_run(tmp_dir):
+ host_artifacts = Path('/checkout/obj/build/x86_64-unknown-linux-gnu')
+ stage0 = host_artifacts / 'stage0/bin'
+ stage2 = host_artifacts / 'stage2/bin'
+
+ env = dict(os.environ)
+ env['PATH'] = '{}:{}:{}'.format(stage2, stage0, env['PATH'])
+
+ # Copy the test create into `tmp_dir`.
+ test_crate = Path(tmp_dir) / 'uefi_qemu_test'
+ shutil.copytree('/uefi_qemu_test', test_crate)
+
+ # Build the UEFI executable.
+ target = 'x86_64-unknown-uefi'
+ run('cargo',
+ 'build',
+ '--manifest-path',
+ test_crate / 'Cargo.toml',
+ '--target',
+ target,
+ env=env)
+
+ # Create a mock EFI System Partition in a subdirectory.
+ esp = test_crate / 'esp'
+ boot = esp / 'efi/boot'
+ os.makedirs(boot, exist_ok=True)
+
+ # Copy the executable into the ESP.
+ src_exe_path = test_crate / 'target' / target / 'debug/uefi_qemu_test.efi'
+ shutil.copy(src_exe_path, boot / 'bootx64.efi')
+
+ # Run the executable in QEMU and capture the output.
+ qemu = 'qemu-system-x86_64'
+ ovmf_dir = Path('/usr/share/OVMF')
+ ovmf_code = ovmf_dir / 'OVMF_CODE.fd'
+ ovmf_vars = ovmf_dir / 'OVMF_VARS.fd'
+ output = run(qemu,
+ '-display',
+ 'none',
+ '-serial',
+ 'stdio',
+ '-drive',
+ f'if=pflash,format=raw,readonly=on,file={ovmf_code}',
+ '-drive',
+ f'if=pflash,format=raw,readonly=on,file={ovmf_vars}',
+ '-drive',
+ f'format=raw,file=fat:rw:{esp}',
+ capture=True,
+ # Ubuntu 20.04 (which is what the Dockerfile currently
+ # uses) provides QEMU 4.2.1, which segfaults on
+ # shutdown under some circumstances. That has been
+ # fixed in newer versions of QEMU, but for now just
+ # don't check the exit status.
+ check=False).stdout
+
+ if 'Hello World!' in output:
+ print('VM produced expected output')
+ else:
+ print('unexpected VM output:')
+ print('---start---')
+ print(output)
+ print('---end---')
+ sys.exit(1)
+
+
+def main():
+ # Create a temporary directory so that we have a writeable
+ # workspace.
+ with tempfile.TemporaryDirectory() as tmp_dir:
+ build_and_run(tmp_dir)
+
+
+if __name__ == "__main__":
+ main()
--- /dev/null
+// Code is adapted from this hello world example:
+// https://doc.rust-lang.org/nightly/rustc/platform-support/unknown-uefi.html
+
+#![no_main]
+#![no_std]
+
+use core::{panic, ptr};
+use r_efi::efi::{Char16, Handle, Status, SystemTable, RESET_SHUTDOWN};
+
+#[panic_handler]
+fn panic_handler(_info: &panic::PanicInfo) -> ! {
+ loop {}
+}
+
+#[export_name = "efi_main"]
+pub extern "C" fn main(_h: Handle, st: *mut SystemTable) -> Status {
+ let s = [
+ 0x0048u16, 0x0065u16, 0x006cu16, 0x006cu16, 0x006fu16, // "Hello"
+ 0x0020u16, // " "
+ 0x0057u16, 0x006fu16, 0x0072u16, 0x006cu16, 0x0064u16, // "World"
+ 0x0021u16, // "!"
+ 0x000au16, // "\n"
+ 0x0000u16, // NUL
+ ];
+
+ // Print "Hello World!".
+ let r = unsafe { ((*(*st).con_out).output_string)((*st).con_out, s.as_ptr() as *mut Char16) };
+ if r.is_error() {
+ return r;
+ }
+
+ // Shut down.
+ unsafe {
+ ((*((*st).runtime_services)).reset_system)(
+ RESET_SHUTDOWN,
+ Status::SUCCESS,
+ 0,
+ ptr::null_mut(),
+ );
+ }
+
+ // This should never be reached because `reset_system` should never
+ // return, so fail with an error if we get here.
+ Status::UNSUPPORTED
+}
# We are disabling CI LLVM since this builder is intentionally using a host
# LLVM, rather than the typical src/llvm-project LLVM.
ENV NO_DOWNLOAD_CI_LLVM 1
-ENV EXTERNAL_LLVM 1
# Using llvm-link-shared due to libffi issues -- see #34486
ENV RUST_CONFIGURE_ARGS \
# We are disabling CI LLVM since this builder is intentionally using a host
# LLVM, rather than the typical src/llvm-project LLVM.
ENV NO_DOWNLOAD_CI_LLVM 1
-ENV EXTERNAL_LLVM 1
# Using llvm-link-shared due to libffi issues -- see #34486
ENV RUST_CONFIGURE_ARGS \
python3 "$X_PY" test --stage 2 src/tools/miri
# We natively run this script on x86_64-unknown-linux-gnu and x86_64-pc-windows-msvc.
# Also cover some other targets (on both of these hosts) via cross-testing.
+export BOOTSTRAP_SKIP_TARGET_SANITY=1 # we don't need `cc` for these targets
python3 "$X_PY" test --stage 2 src/tools/miri --target i686-pc-windows-msvc
-#FIXME(https://github.com/rust-lang/rust/issues/103519): macOS testing is currently disabled
-# python3 "$X_PY" test --stage 2 src/tools/miri --target aarch64-apple-darwin
+python3 "$X_PY" test --stage 2 src/tools/miri --target aarch64-apple-darwin
+unset BOOTSTRAP_SKIP_TARGET_SANITY
# space required for CI artifacts.
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --dist-compression-formats=xz"
-# Enable the `c` feature for compiler_builtins, but only when the `compiler-rt` source is available.
-if [ "$EXTERNAL_LLVM" = "" ]; then
- RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.optimized-compiler-builtins"
-fi
-
if [ "$DIST_SRC" = "" ]; then
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-dist-src"
fi
- [\*-kmc-solid_\*](platform-support/kmc-solid.md)
- [m68k-unknown-linux-gnu](platform-support/m68k-unknown-linux-gnu.md)
- [mips64-openwrt-linux-musl](platform-support/mips64-openwrt-linux-musl.md)
+ - [mipsel-sony-psx](platform-support/mipsel-sony-psx.md)
- [nvptx64-nvidia-cuda](platform-support/nvptx64-nvidia-cuda.md)
- [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md)
- [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md)
debug information. On other Unix platforms this means that `*.dwo` files will
contain debug information.
-Note that `packed` and `unpacked` are gated behind `-Z unstable-options` on
-non-macOS platforms at this time.
+Note that all three options are supported on Linux and Apple platforms,
+`packed` is supported on Windows-MSVC, and all other platforms support `off`.
+Attempting to use an unsupported option requires using the nightly channel
+with the `-Z unstable-options` flag.
## strip
## Toolchain Compatibility
-<!-- NOTE: to update the below table, you can use this shell script:
-
-```sh
-rustup toolchain install --profile minimal nightly
-MINOR_VERSION=$(rustc +nightly --version | cut -d . -f 2)
-LOWER_BOUND=61
-
-llvm_version() {
- toolchain="$1"
- printf "Rust $toolchain | Clang "
- rustc +"$toolchain" -Vv | grep LLVM | cut -d ':' -f 2 | tr -d ' '
-}
-
-for version in `seq $LOWER_BOUND $((MINOR_VERSION - 2))`; do
- toolchain=1.$version.0
- rustup toolchain install --no-self-update --profile minimal $toolchain >/dev/null 2>&1
- llvm_version $toolchain
-done
+<!-- NOTE: to update the below table, you can use this Python script:
+
+```python
+from collections import defaultdict
+import subprocess
+
+def minor_version(version):
+ return int(version.split('.')[1])
+
+INSTALL_TOOLCHAIN = ["rustup", "toolchain", "install", "--profile", "minimal"]
+subprocess.run(INSTALL_TOOLCHAIN + ["nightly"])
+
+LOWER_BOUND = 65
+NIGHTLY_VERSION = minor_version(subprocess.run(
+ ["rustc", "+nightly", "--version"],
+ capture_output=True,
+ text=True).stdout)
+
+def llvm_version(toolchain):
+ version_text = subprocess.run(
+ ["rustc", "+{}".format(toolchain), "-Vv"],
+ capture_output=True,
+ text=True).stdout
+ return int(version_text.split("LLVM")[1].split(':')[1].split('.')[0])
+
+version_map = defaultdict(lambda: [])
+for version in range(LOWER_BOUND, NIGHTLY_VERSION - 1):
+ toolchain = "1.{}.0".format(version)
+ subprocess.run(
+ INSTALL_TOOLCHAIN + ["--no-self-update", toolchain],
+ capture_output=True)
+ version_map[llvm_version(toolchain)].append(version)
+
+print("| Rust Version | Clang Version |")
+print("|--------------|---------------|")
+for clang, rust in sorted(version_map.items()):
+ if len(rust) > 1:
+ rust_range = "1.{} - 1.{}".format(rust[0], rust[-1])
+ else:
+ rust_range = "1.{} ".format(rust[0])
+ print("| {} | {} |".format(rust_range, clang))
```
-->
| Rust Version | Clang Version |
|--------------|---------------|
-| Rust 1.34 | Clang 8 |
-| Rust 1.35 | Clang 8 |
-| Rust 1.36 | Clang 8 |
-| Rust 1.37 | Clang 8 |
-| Rust 1.38 | Clang 9 |
-| Rust 1.39 | Clang 9 |
-| Rust 1.40 | Clang 9 |
-| Rust 1.41 | Clang 9 |
-| Rust 1.42 | Clang 9 |
-| Rust 1.43 | Clang 9 |
-| Rust 1.44 | Clang 9 |
-| Rust 1.45 | Clang 10 |
-| Rust 1.46 | Clang 10 |
-| Rust 1.47 | Clang 11 |
-| Rust 1.48 | Clang 11 |
-| Rust 1.49 | Clang 11 |
-| Rust 1.50 | Clang 11 |
-| Rust 1.51 | Clang 11 |
-| Rust 1.52 | Clang 12 |
-| Rust 1.53 | Clang 12 |
-| Rust 1.54 | Clang 12 |
-| Rust 1.55 | Clang 12 |
-| Rust 1.56 | Clang 13 |
-| Rust 1.57 | Clang 13 |
-| Rust 1.58 | Clang 13 |
-| Rust 1.59 | Clang 13 |
-| Rust 1.60 | Clang 14 |
+| 1.34 - 1.37 | 8 |
+| 1.38 - 1.44 | 9 |
+| 1.45 - 1.46 | 10 |
+| 1.47 - 1.51 | 11 |
+| 1.52 - 1.55 | 12 |
+| 1.56 - 1.59 | 13 |
+| 1.60 - 1.64 | 14 |
+| 1.65 | 15 |
Note that the compatibility policy for this feature might change in the future.
`mips-unknown-linux-uclibc` | ✓ | | MIPS Linux with uClibc
[`mips64-openwrt-linux-musl`](platform-support/mips64-openwrt-linux-musl.md) | ? | | MIPS64 for OpenWrt Linux MUSL
`mipsel-sony-psp` | * | | MIPS (LE) Sony PlayStation Portable (PSP)
+[`mipsel-sony-psx`](platform-support/mipsel-sony-psx.md) | * | | MIPS (LE) Sony PlayStation 1 (PSX)
`mipsel-unknown-linux-uclibc` | ✓ | | MIPS (LE) Linux with uClibc
`mipsel-unknown-none` | * | | Bare MIPS (LE) softfloat
`mipsisa32r6-unknown-linux-gnu` | ? | |
--- /dev/null
+# mipsel-sony-psx
+
+**Tier: 3**
+
+Sony PlayStation 1 (psx)
+
+## Designated Developer
+
+* [@ayrtonm](https://github.com/ayrtonm)
+
+## Requirements
+
+This target is cross-compiled.
+It has no special requirements for the host.
+
+## Building
+
+The target can be built by enabling it for a `rustc` build:
+
+```toml
+[build]
+build-stage = 1
+target = ["mipsel-sony-psx"]
+```
+
+## Cross-compilation
+
+This target can be cross-compiled from any host.
+
+## Testing
+
+Currently there is no support to run the rustc test suite for this target.
+
+## Building Rust programs
+
+Since it is Tier 3, rust doesn't ship pre-compiled artifacts for this target.
+
+Just use the `build-std` nightly cargo feature to build the `core` and `alloc` libraries:
+```shell
+cargo build -Zbuild-std=core,alloc --target mipsel-sony-psx
+```
+
+The command above generates an ELF. To generate binaries in the PSEXE format that emulators run, you can use [cargo-psx](https://github.com/ayrtonm/psx-sdk-rs#readme):
+
+```shell
+cargo psx build
+```
+
+or use `-Clink-arg=--oformat=binary` to produce a flat binary.
## Table of Contents
* [General](#general)
+* [Adding a new target](#adding-a-new-target)
* [Tier 3 target policy](#tier-3-target-policy)
* [Tier 2 target policy](#tier-2-target-policy)
* [Tier 2 with host tools](#tier-2-with-host-tools)
recommendations. This language is based on [IETF RFC
2119](https://tools.ietf.org/html/rfc2119).
+## Adding a new target
+
+New targets typically start as Tier 3 and then can be promoted later.
+To propose addition of a new target, open a pull request on [`rust-lang/rust`]:
+
+- Copy the [Tier 3 target policy](#tier-3-target-policy) to the description
+ and fill it out, see [example][tier3example].
+- Add a new description for the target in `src/doc/rustc/src/platform-support`
+ using the [template][platform_template].
+- Add the target to the [SUMMARY.md][summary] (allows wildcards) and
+ [platform-support.md][platformsupport] (must name all targets verbatim).
+ Link to the created description page.
+- Ensure the pull request is assigned to a member of the [Rust compiler team][rust_compiler_team] by commenting:
+ ```text
+ r? compiler-team
+ ```
+
+[tier3example]: https://github.com/rust-lang/rust/pull/94872
+[platform_template]: https://github.com/rust-lang/rust/blob/master/src/doc/rustc/src/platform-support/TEMPLATE.md
+[summary]: https://github.com/rust-lang/rust/blob/master/src/doc/rustc/src/SUMMARY.md
+[platformsupport]: https://github.com/rust-lang/rust/blob/master/src/doc/rustc/src/platform-support.md
+[rust_compiler_team]: https://www.rust-lang.org/governance/teams/compiler
+[`rust-lang/rust`]: https://github.com/rust-lang/rust
+
## Tier 3 target policy
At this tier, the Rust project provides no official support for a target, so we
git-repository-url = "https://github.com/rust-lang/rust/tree/master/src/doc/rustdoc"
[output.html.redirect]
+"/what-to-include.html" = "write-documentation/what-to-include.html"
"/the-doc-attribute.html" = "write-documentation/the-doc-attribute.html"
+"/linking-to-items-by-name.html" = "write-documentation/linking-to-items-by-name.html"
"/documentation-tests.html" = "write-documentation/documentation-tests.html"
+"/website-features.html" = "advanced-features.html#custom-search-engines"
+"/passes.html" = "deprecated-features.html#passes"
--- /dev/null
+# `extended_varargs_abi_support`
+
+The tracking issue for this feature is: [#100189]
+
+[#100189]: https://github.com/rust-lang/rust/issues/100189
+
+------------------------
+
+This feature adds the possibility of using `sysv64`, `win64` or `efiapi` calling
+conventions on functions with varargs.
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
- <Type Name="str">
+ <Type Name="ref$<str$>">
+ <AlternativeType Name="ref_mut$<str$>" />
+ <AlternativeType Name="ptr_const$<str$>" />
+ <AlternativeType Name="ptr_mut$<str$>" />
+
<DisplayString>{(char*)data_ptr,[length]s8}</DisplayString>
<StringView>(char*)data_ptr,[length]s8</StringView>
<Expand>
</Synthetic>
</Expand>
</Type>
- <Type Name="slice$<*>">
+ <Type Name="ref$<slice2$<*> >">
+ <AlternativeType Name="ref_mut$<slice2$<*> >" />
+ <AlternativeType Name="ptr_const$<slice2$<*> >" />
+ <AlternativeType Name="ptr_mut$<slice2$<*> >" />
+
<DisplayString>{{ len={length} }}</DisplayString>
<Expand>
<Item Name="[len]" ExcludeView="simple">length</Item>
</Type>
<!-- alloc::rc::Rc<[T]> -->
- <Type Name="alloc::rc::Rc<slice$<*> >">
+ <Type Name="alloc::rc::Rc<slice2$<*> >">
<DisplayString>{{ len={ptr.pointer.length} }}</DisplayString>
<Expand>
<Item Name="[Length]" ExcludeView="simple">ptr.pointer.length</Item>
</Type>
<!-- alloc::rc::Weak<[T]> -->
- <Type Name="alloc::rc::Weak<slice$<*> >">
+ <Type Name="alloc::rc::Weak<slice2$<*> >">
<DisplayString>{{ len={ptr.pointer.length} }}</DisplayString>
<Expand>
<Item Name="[Length]" ExcludeView="simple">ptr.pointer.length</Item>
</Type>
<!-- alloc::sync::Arc<[T]> -->
- <Type Name="alloc::sync::Arc<slice$<*> >">
+ <Type Name="alloc::sync::Arc<slice2$<*> >">
<DisplayString>{{ len={ptr.pointer.length} }}</DisplayString>
<Expand>
<Item Name="[Length]" ExcludeView="simple">ptr.pointer.length</Item>
</Type>
<!-- alloc::sync::Weak<[T]> -->
- <Type Name="alloc::sync::Weak<slice$<*> >">
+ <Type Name="alloc::sync::Weak<slice2$<*> >">
<DisplayString>{{ len={ptr.pointer.length} }}</DisplayString>
<Expand>
<Item Name="[Length]" ExcludeView="simple">ptr.pointer.length</Item>
serde = { version = "1.0", features = ["derive"] }
smallvec = "1.8.1"
tempfile = "3"
-thin-vec = "0.2.8"
+thin-vec = "0.2.9"
tracing = "0.1"
tracing-tree = "0.2.0"
use rustc_hir::lang_items::LangItem;
use rustc_middle::ty::{self, Region, RegionVid, TypeFoldable, TypeSuperFoldable};
use rustc_trait_selection::traits::auto_trait::{self, AutoTraitResult};
+use thin_vec::ThinVec;
use std::fmt::Debug;
);
let params = raw_generics.params;
- Generics { params, where_predicates: Vec::new() }
+ Generics { params, where_predicates: ThinVec::new() }
}
AutoTraitResult::ExplicitImpl => return None,
};
Some(Item {
name: None,
attrs: Default::default(),
- visibility: Inherited,
item_id: ItemId::Auto { trait_: trait_def_id, for_: item_def_id },
kind: Box::new(ImplItem(Box::new(Impl {
unsafety: hir::Unsafety::Normal,
kind: ImplKind::Auto,
}))),
cfg: None,
+ inline_stmt_id: None,
})
}
})
.collect();
// We are only interested in case the type *doesn't* implement the Sized trait.
- if !ty.is_sized(tcx.at(rustc_span::DUMMY_SP), param_env) {
+ if !ty.is_sized(tcx, param_env) {
// In case `#![no_core]` is used, `sized_trait` returns nothing.
if let Some(item) = tcx.lang_items().sized_trait().and_then(|sized_trait_did| {
self.generate_for_trait(ty, sized_trait_did, param_env, item_def_id, &f, true)
fn handle_lifetimes<'cx>(
regions: &RegionConstraintData<'cx>,
names_map: &FxHashMap<Symbol, Lifetime>,
- ) -> Vec<WherePredicate> {
+ ) -> ThinVec<WherePredicate> {
// Our goal is to 'flatten' the list of constraints by eliminating
// all intermediate RegionVids. At the end, all constraints should
// be between Regions (aka region variables). This gives us the information
match br {
// We only care about named late bound regions, as we need to add them
// to the 'for<>' section
- ty::BrNamed(_, name) => Some(GenericParamDef {
- name,
- kind: GenericParamDefKind::Lifetime { outlives: vec![] },
- }),
+ ty::BrNamed(_, name) => Some(GenericParamDef::lifetime(name)),
_ => None,
}
})
&mut self,
item_def_id: DefId,
param_env: ty::ParamEnv<'tcx>,
- mut existing_predicates: Vec<WherePredicate>,
+ mut existing_predicates: ThinVec<WherePredicate>,
vid_to_region: FxHashMap<ty::RegionVid, ty::Region<'tcx>>,
) -> Generics {
debug!(
/// both for visual consistency between 'rustdoc' runs, and to
/// make writing tests much easier
#[inline]
- fn sort_where_predicates(&self, predicates: &mut Vec<WherePredicate>) {
+ fn sort_where_predicates(&self, predicates: &mut [WherePredicate]) {
// We should never have identical bounds - and if we do,
// they're visually identical as well. Therefore, using
// an unstable sort is fine.
/// approach is probably somewhat slower, but the small number of items
/// involved (impls rarely have more than a few bounds) means that it
/// shouldn't matter in practice.
- fn unstable_debug_sort<T: Debug>(&self, vec: &mut Vec<T>) {
+ fn unstable_debug_sort<T: Debug>(&self, vec: &mut [T]) {
vec.sort_by_cached_key(|x| format!("{:?}", x))
}
trace!("get_blanket_impls({:?})", ty);
let mut impls = Vec::new();
for trait_def_id in cx.tcx.all_traits() {
- if !cx.cache.access_levels.is_public(trait_def_id)
+ if !cx.cache.effective_visibilities.is_directly_public(cx.tcx, trait_def_id)
|| cx.generated_synthetics.get(&(ty.0, trait_def_id)).is_some()
{
continue;
impls.push(Item {
name: None,
attrs: Default::default(),
- visibility: Inherited,
item_id: ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
kind: Box::new(ImplItem(Box::new(Impl {
unsafety: hir::Unsafety::Normal,
))),
}))),
cfg: None,
+ inline_stmt_id: None,
});
}
}
use std::iter::once;
use std::sync::Arc;
-use thin_vec::ThinVec;
+use thin_vec::{thin_vec, ThinVec};
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashSet;
use crate::clean::{
self, clean_fn_decl_from_did_and_sig, clean_generics, clean_impl_item, clean_middle_assoc_item,
clean_middle_field, clean_middle_ty, clean_trait_ref_with_bindings, clean_ty,
- clean_ty_generics, clean_variant_def, clean_visibility, utils, Attributes, AttributesExt,
- ImplKind, ItemId, Type, Visibility,
+ clean_ty_generics, clean_variant_def, utils, Attributes, AttributesExt, ImplKind, ItemId, Type,
};
use crate::core::DocContext;
use crate::formats::item_type::ItemType;
let mut ret = Vec::new();
debug!("attrs={:?}", attrs);
- let attrs_clone = attrs;
+
+ let attrs_without_docs = attrs.map(|attrs| {
+ attrs.into_iter().filter(|a| a.doc_str().is_none()).cloned().collect::<Vec<_>>()
+ });
+ // We need this ugly code because:
+ //
+ // ```
+ // attrs_without_docs.map(|a| a.as_slice())
+ // ```
+ //
+ // will fail because it returns a temporary slice and:
+ //
+ // ```
+ // attrs_without_docs.map(|s| {
+ // vec = s.as_slice();
+ // vec
+ // })
+ // ```
+ //
+ // will fail because we're moving an uninitialized variable into a closure.
+ let vec;
+ let attrs_without_docs = match attrs_without_docs {
+ Some(s) => {
+ vec = s;
+ Some(vec.as_slice())
+ }
+ None => None,
+ };
let kind = match res {
Res::Def(DefKind::Trait, did) => {
record_extern_fqn(cx, did, ItemType::Trait);
- build_impls(cx, Some(parent_module), did, attrs, &mut ret);
+ build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret);
clean::TraitItem(Box::new(build_external_trait(cx, did)))
}
Res::Def(DefKind::Fn, did) => {
}
Res::Def(DefKind::Struct, did) => {
record_extern_fqn(cx, did, ItemType::Struct);
- build_impls(cx, Some(parent_module), did, attrs, &mut ret);
+ build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret);
clean::StructItem(build_struct(cx, did))
}
Res::Def(DefKind::Union, did) => {
record_extern_fqn(cx, did, ItemType::Union);
- build_impls(cx, Some(parent_module), did, attrs, &mut ret);
+ build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret);
clean::UnionItem(build_union(cx, did))
}
Res::Def(DefKind::TyAlias, did) => {
record_extern_fqn(cx, did, ItemType::Typedef);
- build_impls(cx, Some(parent_module), did, attrs, &mut ret);
+ build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret);
clean::TypedefItem(build_type_alias(cx, did))
}
Res::Def(DefKind::Enum, did) => {
record_extern_fqn(cx, did, ItemType::Enum);
- build_impls(cx, Some(parent_module), did, attrs, &mut ret);
+ build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret);
clean::EnumItem(build_enum(cx, did))
}
Res::Def(DefKind::ForeignTy, did) => {
record_extern_fqn(cx, did, ItemType::ForeignType);
- build_impls(cx, Some(parent_module), did, attrs, &mut ret);
+ build_impls(cx, Some(parent_module), did, attrs_without_docs, &mut ret);
clean::ForeignTypeItem
}
// Never inline enum variants but leave them shown as re-exports.
_ => return None,
};
- let (attrs, cfg) = merge_attrs(cx, Some(parent_module), load_attrs(cx, did), attrs_clone);
+ let (attrs, cfg) = merge_attrs(cx, Some(parent_module), load_attrs(cx, did), attrs);
cx.inlined.insert(did.into());
- let mut item = clean::Item::from_def_id_and_attrs_and_parts(
- did,
- Some(name),
- kind,
- Box::new(attrs),
- cx,
- cfg,
- );
- if let Some(import_def_id) = import_def_id {
- // The visibility needs to reflect the one from the reexport and not from the "source" DefId.
- item.visibility = clean_visibility(cx.tcx.visibility(import_def_id));
- }
+ let mut item =
+ clean::Item::from_def_id_and_attrs_and_parts(did, Some(name), kind, Box::new(attrs), cfg);
+ // The visibility needs to reflect the one from the reexport and not from the "source" DefId.
+ item.inline_stmt_id = import_def_id;
ret.push(item);
Some(ret)
}
.tcx
.associated_items(did)
.in_definition_order()
- .map(|item| {
- // When building an external trait, the cleaned trait will have all items public,
- // which causes methods to have a `pub` prefix, which is invalid since items in traits
- // can not have a visibility prefix. Thus we override the visibility here manually.
- // See https://github.com/rust-lang/rust/issues/81274
- clean::Item { visibility: Visibility::Inherited, ..clean_middle_assoc_item(item, cx) }
- })
+ .map(|item| clean_middle_assoc_item(item, cx))
.collect();
let predicates = cx.tcx.predicates_of(did);
fn build_external_function<'tcx>(cx: &mut DocContext<'tcx>, did: DefId) -> Box<clean::Function> {
let sig = cx.tcx.fn_sig(did);
- let predicates = cx.tcx.predicates_of(did);
+ let late_bound_regions = sig.bound_vars().into_iter().filter_map(|var| match var {
+ ty::BoundVariableKind::Region(ty::BrNamed(_, name)) if name != kw::UnderscoreLifetime => {
+ Some(clean::GenericParamDef::lifetime(name))
+ }
+ _ => None,
+ });
+
+ let predicates = cx.tcx.explicit_predicates_of(did);
let (generics, decl) = clean::enter_impl_trait(cx, |cx| {
// NOTE: generics need to be cleaned before the decl!
- let generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates);
+ let mut generics = clean_ty_generics(cx, cx.tcx.generics_of(did), predicates);
+ // FIXME: This does not place parameters in source order (late-bound ones come last)
+ generics.params.extend(late_bound_regions);
let decl = clean_fn_decl_from_did_and_sig(cx, Some(did), sig);
(generics, decl)
});
for &did in tcx.inherent_impls(did).iter() {
build_impl(cx, parent_module, did, attrs, ret);
}
+
+ // This pretty much exists expressly for `dyn Error` traits that exist in the `alloc` crate.
+ // See also:
+ //
+ // * https://github.com/rust-lang/rust/issues/103170 — where it didn't used to get documented
+ // * https://github.com/rust-lang/rust/pull/99917 — where the feature got used
+ // * https://github.com/rust-lang/rust/issues/53487 — overall tracking issue for Error
+ if tcx.has_attr(did, sym::rustc_has_incoherent_inherent_impls) {
+ use rustc_middle::ty::fast_reject::SimplifiedTypeGen::*;
+ let type_ =
+ if tcx.is_trait(did) { TraitSimplifiedType(did) } else { AdtSimplifiedType(did) };
+ for &did in tcx.incoherent_impls(type_) {
+ build_impl(cx, parent_module, did, attrs, ret);
+ }
+ }
}
/// `parent_module` refers to the parent of the re-export, not the original item
if !did.is_local() {
if let Some(traitref) = associated_trait {
let did = traitref.def_id;
- if !cx.cache.access_levels.is_public(did) {
+ if !cx.cache.effective_visibilities.is_directly_public(tcx, did) {
return;
}
// reachable in rustdoc generated documentation
if !did.is_local() {
if let Some(did) = for_.def_id(&cx.cache) {
- if !cx.cache.access_levels.is_public(did) {
+ if !cx.cache.effective_visibilities.is_directly_public(tcx, did) {
return;
}
},
})),
Box::new(merged_attrs),
- cx,
cfg,
));
}
name: None,
attrs: Box::new(clean::Attributes::default()),
item_id: ItemId::Primitive(prim_ty, did.krate),
- visibility: clean::Public,
kind: Box::new(clean::ImportItem(clean::Import::new_simple(
item.ident.name,
clean::ImportSource {
path: clean::Path {
res,
- segments: vec![clean::PathSegment {
+ segments: thin_vec![clean::PathSegment {
name: prim_ty.as_sym(),
args: clean::GenericArgs::AngleBracketed {
args: Default::default(),
true,
))),
cfg: None,
+ inline_stmt_id: None,
});
} else if let Some(i) = try_inline(cx, did, None, res, item.ident.name, None, visited) {
items.extend(i)
match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.sess()) {
LoadedMacro::MacroDef(item_def, _) => {
if let ast::ItemKind::MacroDef(ref def) = item_def.kind {
- let vis = clean_visibility(cx.tcx.visibility(import_def_id.unwrap_or(def_id)));
+ let vis = cx.tcx.visibility(import_def_id.unwrap_or(def_id));
clean::MacroItem(clean::Macro {
source: utils::display_macro_source(cx, name, def, def_id, vis),
})
use rustc_ast as ast;
use rustc_attr as attr;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
// This covers the case where somebody does an import which should pull in an item,
// but there's already an item with the same namespace and same name. Rust gives
// priority to the not-imported one, so we should, too.
- items.extend(doc.items.iter().flat_map(|(item, renamed)| {
+ items.extend(doc.items.iter().flat_map(|(item, renamed, import_id)| {
// First, lower everything other than imports.
if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
return Vec::new();
}
- let v = clean_maybe_renamed_item(cx, item, *renamed);
+ let v = clean_maybe_renamed_item(cx, item, *renamed, *import_id);
for item in &v {
if let Some(name) = item.name && !item.attrs.lists(sym::doc).has_word(sym::hidden) {
inserted.insert((item.type_(), name));
}
v
}));
- items.extend(doc.items.iter().flat_map(|(item, renamed)| {
+ items.extend(doc.items.iter().flat_map(|(item, renamed, _)| {
// Now we actually lower the imports, skipping everything else.
if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind {
let name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id()));
.collect_referenced_late_bound_regions(&poly_trait_ref)
.into_iter()
.filter_map(|br| match br {
- ty::BrNamed(_, name) if name != kw::UnderscoreLifetime => Some(GenericParamDef {
- name,
- kind: GenericParamDefKind::Lifetime { outlives: vec![] },
- }),
+ ty::BrNamed(_, name) if name != kw::UnderscoreLifetime => {
+ Some(GenericParamDef::lifetime(name))
+ }
_ => None,
})
.collect();
// FIXME: instead of storing the stringified expression, store `self` directly instead.
Constant {
type_: clean_middle_ty(constant.ty(), cx, None),
- kind: ConstantKind::TyConst { expr: constant.to_string() },
+ kind: ConstantKind::TyConst { expr: constant.to_string().into() },
}
}
cx: &mut DocContext<'tcx>,
def_id: Option<DefId>,
) -> Type {
+ if cx.tcx.def_kind(ty.item_def_id) == DefKind::ImplTraitPlaceholder {
+ let bounds = cx
+ .tcx
+ .explicit_item_bounds(ty.item_def_id)
+ .iter()
+ .map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, ty.substs))
+ .collect::<Vec<_>>();
+ return clean_middle_opaque_bounds(cx, bounds);
+ }
+
let trait_ = clean_trait_ref_with_bindings(cx, ty.trait_ref(cx.tcx), ThinVec::new());
let self_type = clean_middle_ty(ty.self_ty(), cx, None);
let self_def_id = if let Some(def_id) = def_id {
})
.collect::<Vec<_>>();
- let mut params = Vec::with_capacity(gens.params.len());
+ let mut params = ThinVec::with_capacity(gens.params.len());
for p in gens.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) {
let p = clean_generic_param(cx, Some(gens), p);
params.push(p);
}
ty::GenericParamDefKind::Const { .. } => Some(clean_generic_param_def(param, cx)),
})
- .collect::<Vec<GenericParamDef>>();
+ .collect::<ThinVec<GenericParamDef>>();
// param index -> [(trait DefId, associated type name & generics, type, higher-ranked params)]
let mut impl_trait_proj =
p.get_bound_params()
.into_iter()
.flatten()
- .map(|param| GenericParamDef {
- name: param.0,
- kind: GenericParamDefKind::Lifetime { outlives: Vec::new() },
- })
+ .map(|param| GenericParamDef::lifetime(param.0))
.collect(),
));
}
ProcMacroItem(ProcMacro { kind, helpers })
}
None => {
- let mut func = clean_function(cx, sig, generics, body_id);
+ let mut func = clean_function(cx, sig, generics, FunctionArgs::Body(body_id));
clean_fn_decl_legacy_const_generics(&mut func, attrs);
FunctionItem(func)
}
}
}
+enum FunctionArgs<'tcx> {
+ Body(hir::BodyId),
+ Names(&'tcx [Ident]),
+}
+
fn clean_function<'tcx>(
cx: &mut DocContext<'tcx>,
sig: &hir::FnSig<'tcx>,
generics: &hir::Generics<'tcx>,
- body_id: hir::BodyId,
+ args: FunctionArgs<'tcx>,
) -> Box<Function> {
let (generics, decl) = enter_impl_trait(cx, |cx| {
// NOTE: generics must be cleaned before args
let generics = clean_generics(generics, cx);
- let args = clean_args_from_types_and_body_id(cx, sig.decl.inputs, body_id);
+ let args = match args {
+ FunctionArgs::Body(body_id) => {
+ clean_args_from_types_and_body_id(cx, sig.decl.inputs, body_id)
+ }
+ FunctionArgs::Names(names) => {
+ clean_args_from_types_and_names(cx, sig.decl.inputs, names)
+ }
+ };
let mut decl = clean_fn_decl_with_args(cx, sig.decl, args);
if sig.header.is_async() {
decl.output = decl.sugared_async_return_type();
values: types
.iter()
.enumerate()
- .map(|(i, ty)| {
- let mut name = names.get(i).map_or(kw::Empty, |ident| ident.name);
- if name.is_empty() {
- name = kw::Underscore;
- }
- Argument { name, type_: clean_ty(ty, cx), is_const: false }
+ .map(|(i, ty)| Argument {
+ type_: clean_ty(ty, cx),
+ name: names
+ .get(i)
+ .map(|ident| ident.name)
+ .filter(|ident| !ident.is_empty())
+ .unwrap_or(kw::Underscore),
+ is_const: false,
})
.collect(),
}
.iter()
.map(|t| Argument {
type_: clean_middle_ty(*t, cx, None),
- name: names.next().map_or(kw::Empty, |i| i.name),
+ name: names
+ .next()
+ .map(|i| i.name)
+ .filter(|i| !i.is_empty())
+ .unwrap_or(kw::Underscore),
is_const: false,
})
.collect(),
}
fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
- let local_did = trait_item.def_id.to_def_id();
+ let local_did = trait_item.owner_id.to_def_id();
cx.with_param_env(local_did, |cx| {
let inner = match trait_item.kind {
hir::TraitItemKind::Const(ty, Some(default)) => AssocConstItem(
),
hir::TraitItemKind::Const(ty, None) => TyAssocConstItem(clean_ty(ty, cx)),
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => {
- let m = clean_function(cx, sig, trait_item.generics, body);
+ let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Body(body));
MethodItem(m, None)
}
hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => {
- let (generics, decl) = enter_impl_trait(cx, |cx| {
- // NOTE: generics must be cleaned before args
- let generics = clean_generics(trait_item.generics, cx);
- let args = clean_args_from_types_and_names(cx, sig.decl.inputs, names);
- let decl = clean_fn_decl_with_args(cx, sig.decl, args);
- (generics, decl)
- });
- TyMethodItem(Box::new(Function { decl, generics }))
+ let m = clean_function(cx, sig, trait_item.generics, FunctionArgs::Names(names));
+ TyMethodItem(m)
}
hir::TraitItemKind::Type(bounds, Some(default)) => {
let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
hir::TraitItemKind::Type(bounds, None) => {
let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx));
let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect();
- TyAssocTypeItem(Box::new(generics), bounds)
+ TyAssocTypeItem(generics, bounds)
}
};
- let what_rustc_thinks =
- Item::from_def_id_and_parts(local_did, Some(trait_item.ident.name), inner, cx);
- // Trait items always inherit the trait's visibility -- we don't want to show `pub`.
- Item { visibility: Inherited, ..what_rustc_thinks }
+ Item::from_def_id_and_parts(local_did, Some(trait_item.ident.name), inner, cx)
})
}
impl_: &hir::ImplItem<'tcx>,
cx: &mut DocContext<'tcx>,
) -> Item {
- let local_did = impl_.def_id.to_def_id();
+ let local_did = impl_.owner_id.to_def_id();
cx.with_param_env(local_did, |cx| {
let inner = match impl_.kind {
hir::ImplItemKind::Const(ty, expr) => {
AssocConstItem(clean_ty(ty, cx), default)
}
hir::ImplItemKind::Fn(ref sig, body) => {
- let m = clean_function(cx, sig, impl_.generics, body);
- let defaultness = cx.tcx.impl_defaultness(impl_.def_id);
+ let m = clean_function(cx, sig, impl_.generics, FunctionArgs::Body(body));
+ let defaultness = cx.tcx.impl_defaultness(impl_.owner_id);
MethodItem(m, Some(defaultness))
}
hir::ImplItemKind::Type(hir_ty) => {
}
};
- let mut what_rustc_thinks =
- Item::from_def_id_and_parts(local_did, Some(impl_.ident.name), inner, cx);
-
- let impl_ref = cx.tcx.impl_trait_ref(cx.tcx.local_parent(impl_.def_id.def_id));
-
- // Trait impl items always inherit the impl's visibility --
- // we don't want to show `pub`.
- if impl_ref.is_some() {
- what_rustc_thinks.visibility = Inherited;
- }
-
- what_rustc_thinks
+ Item::from_def_id_and_parts(local_did, Some(impl_.ident.name), inner, cx)
})
}
}
}
ty::AssocKind::Fn => {
- let generics = clean_ty_generics(
+ let sig = tcx.fn_sig(assoc_item.def_id);
+
+ let late_bound_regions = sig.bound_vars().into_iter().filter_map(|var| match var {
+ ty::BoundVariableKind::Region(ty::BrNamed(_, name))
+ if name != kw::UnderscoreLifetime =>
+ {
+ Some(GenericParamDef::lifetime(name))
+ }
+ _ => None,
+ });
+
+ let mut generics = clean_ty_generics(
cx,
tcx.generics_of(assoc_item.def_id),
tcx.explicit_predicates_of(assoc_item.def_id),
);
- let sig = tcx.fn_sig(assoc_item.def_id);
+ // FIXME: This does not place parameters in source order (late-bound ones come last)
+ generics.params.extend(late_bound_regions);
+
let mut decl = clean_fn_decl_from_did_and_sig(cx, Some(assoc_item.def_id), sig);
if assoc_item.fn_has_self_parameter {
true
}
(GenericParamDefKind::Const { .. }, GenericArg::Const(c)) => match &c.kind {
- ConstantKind::TyConst { expr } => expr == param.name.as_str(),
+ ConstantKind::TyConst { expr } => **expr == *param.name.as_str(),
_ => false,
},
_ => false,
tcx.generics_of(assoc_item.def_id),
ty::GenericPredicates { parent: None, predicates },
);
- // Move bounds that are (likely) directly attached to the associated type
- // from the where clause to the associated type.
- // There is no guarantee that this is what the user actually wrote but we have
- // no way of knowing.
- let mut bounds = generics
- .where_predicates
- .drain_filter(|pred| match *pred {
- WherePredicate::BoundPredicate {
- ty: QPath(box QPathData { ref assoc, ref self_type, ref trait_, .. }),
- ..
- } => {
- if assoc.name != my_name {
- return false;
- }
- if trait_.def_id() != assoc_item.container_id(tcx) {
- return false;
- }
- match *self_type {
- Generic(ref s) if *s == kw::SelfUpper => {}
- _ => return false,
- }
- match &assoc.args {
- GenericArgs::AngleBracketed { args, bindings } => {
- if !bindings.is_empty()
- || generics
- .params
- .iter()
- .zip(args.iter())
- .any(|(param, arg)| !param_eq_arg(param, arg))
- {
- return false;
- }
- }
- GenericArgs::Parenthesized { .. } => {
- // The only time this happens is if we're inside the rustdoc for Fn(),
- // which only has one associated type, which is not a GAT, so whatever.
+ // Filter out the bounds that are (likely?) directly attached to the associated type,
+ // as opposed to being located in the where clause.
+ let mut bounds: Vec<GenericBound> = Vec::new();
+ generics.where_predicates.retain_mut(|pred| match *pred {
+ WherePredicate::BoundPredicate {
+ ty: QPath(box QPathData { ref assoc, ref self_type, ref trait_, .. }),
+ bounds: ref mut pred_bounds,
+ ..
+ } => {
+ if assoc.name != my_name {
+ return true;
+ }
+ if trait_.def_id() != assoc_item.container_id(tcx) {
+ return true;
+ }
+ match *self_type {
+ Generic(ref s) if *s == kw::SelfUpper => {}
+ _ => return true,
+ }
+ match &assoc.args {
+ GenericArgs::AngleBracketed { args, bindings } => {
+ if !bindings.is_empty()
+ || generics
+ .params
+ .iter()
+ .zip(args.iter())
+ .any(|(param, arg)| !param_eq_arg(param, arg))
+ {
+ return true;
}
}
- true
- }
- _ => false,
- })
- .flat_map(|pred| {
- if let WherePredicate::BoundPredicate { bounds, .. } = pred {
- bounds
- } else {
- unreachable!()
+ GenericArgs::Parenthesized { .. } => {
+ // The only time this happens is if we're inside the rustdoc for Fn(),
+ // which only has one associated type, which is not a GAT, so whatever.
+ }
}
- })
- .collect::<Vec<_>>();
+ bounds.extend(mem::replace(pred_bounds, Vec::new()));
+ false
+ }
+ _ => true,
+ });
// Our Sized/?Sized bound didn't get handled when creating the generics
// because we didn't actually get our whole set of bounds until just now
// (some of them may have come from the trait). If we do have a sized
// (generic) associated type from the where clause to the respective parameter.
// There is no guarantee that this is what the user actually wrote but we have
// no way of knowing.
- let mut where_predicates = Vec::new();
+ let mut where_predicates = ThinVec::new();
for mut pred in generics.where_predicates {
if let WherePredicate::BoundPredicate { ty: Generic(arg), bounds, .. } = &mut pred
&& let Some(GenericParamDef {
..
}) = generics.params.iter_mut().find(|param| ¶m.name == arg)
{
- param_bounds.extend(mem::take(bounds));
+ param_bounds.append(bounds);
+ } else if let WherePredicate::RegionPredicate { lifetime: Lifetime(arg), bounds } = &mut pred
+ && let Some(GenericParamDef {
+ kind: GenericParamDefKind::Lifetime { outlives: param_bounds },
+ ..
+ }) = generics.params.iter_mut().find(|param| ¶m.name == arg) {
+ param_bounds.extend(bounds.drain(..).map(|bound| match bound {
+ GenericBound::Outlives(lifetime) => lifetime,
+ _ => unreachable!(),
+ }));
} else {
where_predicates.push(pred);
}
bounds,
)
} else {
- TyAssocTypeItem(Box::new(generics), bounds)
+ TyAssocTypeItem(generics, bounds)
}
} else {
// FIXME: when could this happen? Associated items in inherent impls?
cx,
Some(assoc_item.def_id),
),
- generics: Generics { params: Vec::new(), where_predicates: Vec::new() },
+ generics: Generics {
+ params: ThinVec::new(),
+ where_predicates: ThinVec::new(),
+ },
item_type: None,
}),
Vec::new(),
}
};
- let mut what_rustc_thinks =
- Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name), kind, cx);
-
- let impl_ref = tcx.impl_trait_ref(tcx.parent(assoc_item.def_id));
-
- // Trait impl items always inherit the impl's visibility --
- // we don't want to show `pub`.
- if impl_ref.is_some() {
- what_rustc_thinks.visibility = Visibility::Inherited;
- }
-
- what_rustc_thinks
+ Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name), kind, cx)
}
fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type {
ty::Projection(proj) => Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id),
// Rustdoc handles `ty::Error`s by turning them into `Type::Infer`s.
ty::Error(_) => return Type::Infer,
- _ => bug!("clean: expected associated type, found `{:?}`", ty),
+ // Otherwise, this is an inherent associated type.
+ _ => return clean_middle_ty(ty, cx, None),
};
let trait_ = clean_path(&hir::Path { span, res, segments: &[] }, cx);
register_res(cx, trait_.res);
let Res::Def(DefKind::TyAlias, def_id) = path.res else { return None };
// Substitute private type aliases
let def_id = def_id.as_local()?;
- let alias = if !cx.cache.access_levels.is_exported(def_id.to_def_id()) {
+ let alias = if !cx.cache.effective_visibilities.is_exported(cx.tcx, def_id.to_def_id()) {
&cx.tcx.hir().expect_item(def_id).kind
} else {
return None;
}
};
- Array(Box::new(clean_ty(ty, cx)), length)
+ Array(Box::new(clean_ty(ty, cx)), length.into())
}
TyKind::Tup(tys) => Tuple(tys.iter().map(|ty| clean_ty(ty, cx)).collect()),
TyKind::OpaqueDef(item_id, _, _) => {
ty::Array(ty, mut n) => {
n = n.eval(cx.tcx, ty::ParamEnv::reveal_all());
let n = print_const(cx, n);
- Array(Box::new(clean_middle_ty(ty, cx, None)), n)
+ Array(Box::new(clean_middle_ty(ty, cx, None)), n.into())
}
ty::RawPtr(mt) => RawPointer(mt.mutbl, Box::new(clean_middle_ty(mt.ty, cx, None))),
ty::Ref(r, ty, mutbl) => BorrowedRef {
inline::record_extern_fqn(cx, did, ItemType::Trait);
+ // FIXME(fmease): Hide the trait-object lifetime bound if it coincides with its default
+ // to partially address #44306. Follow the rules outlined at
+ // https://doc.rust-lang.org/reference/lifetime-elision.html#default-trait-object-lifetimes
let lifetime = clean_middle_region(*reg);
let mut bounds = dids
.map(|did| {
})
.collect();
+ let late_bound_regions: FxIndexSet<_> = obj
+ .iter()
+ .flat_map(|pb| pb.bound_vars())
+ .filter_map(|br| match br {
+ ty::BoundVariableKind::Region(ty::BrNamed(_, name))
+ if name != kw::UnderscoreLifetime =>
+ {
+ Some(GenericParamDef::lifetime(name))
+ }
+ _ => None,
+ })
+ .collect();
+ let late_bound_regions = late_bound_regions.into_iter().collect();
+
let path = external_path(cx, did, false, bindings, substs);
- bounds.insert(0, PolyTrait { trait_: path, generic_params: Vec::new() });
+ bounds.insert(0, PolyTrait { trait_: path, generic_params: late_bound_regions });
DynTrait(bounds, lifetime)
}
.iter()
.map(|(bound, _)| EarlyBinder(*bound).subst(cx.tcx, substs))
.collect::<Vec<_>>();
- let mut regions = vec![];
- let mut has_sized = false;
- let mut bounds = bounds
- .iter()
- .filter_map(|bound| {
- let bound_predicate = bound.kind();
- let trait_ref = match bound_predicate.skip_binder() {
- ty::PredicateKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref),
- ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => {
- if let Some(r) = clean_middle_region(reg) {
- regions.push(GenericBound::Outlives(r));
- }
- return None;
- }
- _ => return None,
- };
-
- if let Some(sized) = cx.tcx.lang_items().sized_trait() {
- if trait_ref.def_id() == sized {
- has_sized = true;
- return None;
- }
- }
-
- let bindings: ThinVec<_> = bounds
- .iter()
- .filter_map(|bound| {
- if let ty::PredicateKind::Projection(proj) = bound.kind().skip_binder()
- {
- if proj.projection_ty.trait_ref(cx.tcx) == trait_ref.skip_binder() {
- Some(TypeBinding {
- assoc: projection_to_path_segment(proj.projection_ty, cx),
- kind: TypeBindingKind::Equality {
- term: clean_middle_term(proj.term, cx),
- },
- })
- } else {
- None
- }
- } else {
- None
- }
- })
- .collect();
-
- Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, bindings))
- })
- .collect::<Vec<_>>();
- bounds.extend(regions);
- if !has_sized && !bounds.is_empty() {
- bounds.insert(0, GenericBound::maybe_sized(cx));
- }
- ImplTrait(bounds)
+ clean_middle_opaque_bounds(cx, bounds)
}
ty::Closure(..) => panic!("Closure"),
}
}
+fn clean_middle_opaque_bounds<'tcx>(
+ cx: &mut DocContext<'tcx>,
+ bounds: Vec<ty::Predicate<'tcx>>,
+) -> Type {
+ let mut regions = vec![];
+ let mut has_sized = false;
+ let mut bounds = bounds
+ .iter()
+ .filter_map(|bound| {
+ let bound_predicate = bound.kind();
+ let trait_ref = match bound_predicate.skip_binder() {
+ ty::PredicateKind::Trait(tr) => bound_predicate.rebind(tr.trait_ref),
+ ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(_ty, reg)) => {
+ if let Some(r) = clean_middle_region(reg) {
+ regions.push(GenericBound::Outlives(r));
+ }
+ return None;
+ }
+ _ => return None,
+ };
+
+ if let Some(sized) = cx.tcx.lang_items().sized_trait() {
+ if trait_ref.def_id() == sized {
+ has_sized = true;
+ return None;
+ }
+ }
+
+ let bindings: ThinVec<_> = bounds
+ .iter()
+ .filter_map(|bound| {
+ if let ty::PredicateKind::Projection(proj) = bound.kind().skip_binder() {
+ if proj.projection_ty.trait_ref(cx.tcx) == trait_ref.skip_binder() {
+ Some(TypeBinding {
+ assoc: projection_to_path_segment(proj.projection_ty, cx),
+ kind: TypeBindingKind::Equality {
+ term: clean_middle_term(proj.term, cx),
+ },
+ })
+ } else {
+ None
+ }
+ } else {
+ None
+ }
+ })
+ .collect();
+
+ Some(clean_poly_trait_ref_with_bindings(cx, trait_ref, bindings))
+ })
+ .collect::<Vec<_>>();
+ bounds.extend(regions);
+ if !has_sized && !bounds.is_empty() {
+ bounds.insert(0, GenericBound::maybe_sized(cx));
+ }
+ ImplTrait(bounds)
+}
+
pub(crate) fn clean_field<'tcx>(field: &hir::FieldDef<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
let def_id = cx.tcx.hir().local_def_id(field.hir_id).to_def_id();
clean_field_with_def_id(def_id, field.ident.name, clean_ty(field.ty, cx), cx)
ty: Type,
cx: &mut DocContext<'_>,
) -> Item {
- let what_rustc_thinks =
- Item::from_def_id_and_parts(def_id, Some(name), StructFieldItem(ty), cx);
- if is_field_vis_inherited(cx.tcx, def_id) {
- // Variant fields inherit their enum's visibility.
- Item { visibility: Visibility::Inherited, ..what_rustc_thinks }
- } else {
- what_rustc_thinks
- }
-}
-
-fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
- let parent = tcx.parent(def_id);
- match tcx.def_kind(parent) {
- DefKind::Struct | DefKind::Union => false,
- DefKind::Variant => true,
- parent_kind => panic!("unexpected parent kind: {:?}", parent_kind),
- }
-}
-
-pub(crate) fn clean_visibility(vis: ty::Visibility<DefId>) -> Visibility {
- match vis {
- ty::Visibility::Public => Visibility::Public,
- ty::Visibility::Restricted(module) => Visibility::Restricted(module),
- }
+ Item::from_def_id_and_parts(def_id, Some(name), StructFieldItem(ty), cx)
}
pub(crate) fn clean_variant_def<'tcx>(variant: &ty::VariantDef, cx: &mut DocContext<'tcx>) -> Item {
fields: variant.fields.iter().map(|field| clean_middle_field(field, cx)).collect(),
}),
};
- let what_rustc_thinks =
- Item::from_def_id_and_parts(variant.def_id, Some(variant.name), VariantItem(kind), cx);
- // don't show `pub` for variants, which always inherit visibility
- Item { visibility: Inherited, ..what_rustc_thinks }
+ Item::from_def_id_and_parts(variant.def_id, Some(variant.name), VariantItem(kind), cx)
}
fn clean_variant_data<'tcx>(
cx: &mut DocContext<'tcx>,
item: &hir::Item<'tcx>,
renamed: Option<Symbol>,
+ import_id: Option<hir::HirId>,
) -> Vec<Item> {
use hir::ItemKind;
- let def_id = item.def_id.to_def_id();
+ let def_id = item.owner_id.to_def_id();
let mut name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id()));
cx.with_param_env(def_id, |cx| {
let kind = match item.kind {
clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx)
}
ItemKind::Macro(ref macro_def, _) => {
- let ty_vis = clean_visibility(cx.tcx.visibility(def_id));
+ let ty_vis = cx.tcx.visibility(def_id);
MacroItem(Macro {
source: display_macro_source(cx, name, macro_def, def_id, ty_vis),
})
}
_ => unreachable!("not yet converted"),
};
-
- vec![Item::from_def_id_and_parts(def_id, Some(name), kind, cx)]
+ if let Some(import_id) = import_id {
+ let (attrs, cfg) = inline::merge_attrs(
+ cx,
+ Some(cx.tcx.parent_module(import_id).to_def_id()),
+ inline::load_attrs(cx, def_id),
+ Some(inline::load_attrs(cx, cx.tcx.hir().local_def_id(import_id).to_def_id())),
+ );
+ vec![Item::from_def_id_and_attrs_and_parts(
+ def_id,
+ Some(name),
+ kind,
+ Box::new(attrs),
+ cfg,
+ )]
+ } else {
+ vec![Item::from_def_id_and_parts(def_id, Some(name), kind, cx)]
+ }
})
}
fn clean_variant<'tcx>(variant: &hir::Variant<'tcx>, cx: &mut DocContext<'tcx>) -> Item {
let kind = VariantItem(clean_variant_data(&variant.data, &variant.disr_expr, cx));
- let what_rustc_thinks =
- Item::from_hir_id_and_parts(variant.id, Some(variant.ident.name), kind, cx);
- // don't show `pub` for variants, which are always public
- Item { visibility: Inherited, ..what_rustc_thinks }
+ Item::from_hir_id_and_parts(variant.id, Some(variant.ident.name), kind, cx)
}
fn clean_impl<'tcx>(
cx: &mut DocContext<'tcx>,
) -> Vec<Item> {
// this is the ID of the `extern crate` statement
- let cnum = cx.tcx.extern_mod_stmt_cnum(krate.def_id.def_id).unwrap_or(LOCAL_CRATE);
+ let cnum = cx.tcx.extern_mod_stmt_cnum(krate.owner_id.def_id).unwrap_or(LOCAL_CRATE);
// this is the ID of the crate itself
let crate_def_id = cnum.as_def_id();
let attrs = cx.tcx.hir().attrs(krate.hir_id());
- let ty_vis = cx.tcx.visibility(krate.def_id);
+ let ty_vis = cx.tcx.visibility(krate.owner_id);
let please_inline = ty_vis.is_public()
&& attrs.iter().any(|a| {
a.has_name(sym::doc)
}
});
+ let krate_owner_def_id = krate.owner_id.to_def_id();
if please_inline {
let mut visited = FxHashSet::default();
if let Some(items) = inline::try_inline(
cx,
cx.tcx.parent_module(krate.hir_id()).to_def_id(),
- Some(krate.def_id.to_def_id()),
+ Some(krate_owner_def_id),
res,
name,
Some(attrs),
name: Some(name),
attrs: Box::new(Attributes::from_ast(attrs)),
item_id: crate_def_id.into(),
- visibility: clean_visibility(ty_vis),
kind: Box::new(ExternCrateItem { src: orig_name }),
cfg: attrs.cfg(cx.tcx, &cx.cache.hidden_cfg),
+ inline_stmt_id: Some(krate_owner_def_id),
}]
}
return Vec::new();
}
- let visibility = cx.tcx.visibility(import.def_id);
+ let visibility = cx.tcx.visibility(import.owner_id);
let attrs = cx.tcx.hir().attrs(import.hir_id());
let inline_attr = attrs.lists(sym::doc).get_word_attr(sym::inline);
let pub_underscore = visibility.is_public() && name == kw::Underscore;
- let current_mod = cx.tcx.parent_module_from_def_id(import.def_id.def_id);
+ let current_mod = cx.tcx.parent_module_from_def_id(import.owner_id.def_id);
// The parent of the module in which this import resides. This
// is the same as `current_mod` if that's already the top
}
if !denied {
let mut visited = FxHashSet::default();
- let import_def_id = import.def_id.to_def_id();
+ let import_def_id = import.owner_id.to_def_id();
if let Some(mut items) = inline::try_inline(
cx,
Import::new_simple(name, resolve_use_source(cx, path), true)
};
- vec![Item::from_def_id_and_parts(import.def_id.to_def_id(), None, ImportItem(inner), cx)]
+ vec![Item::from_def_id_and_parts(import.owner_id.to_def_id(), None, ImportItem(inner), cx)]
}
fn clean_maybe_renamed_foreign_item<'tcx>(
item: &hir::ForeignItem<'tcx>,
renamed: Option<Symbol>,
) -> Item {
- let def_id = item.def_id.to_def_id();
+ let def_id = item.owner_id.to_def_id();
cx.with_param_env(def_id, |cx| {
let kind = match item.kind {
hir::ForeignItemKind::Fn(decl, names, generics) => {
use rustc_data_structures::fx::FxIndexMap;
use rustc_hir::def_id::DefId;
use rustc_middle::ty;
+use thin_vec::ThinVec;
use crate::clean;
use crate::clean::GenericArgs as PP;
use crate::clean::WherePredicate as WP;
use crate::core::DocContext;
-pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> Vec<WP> {
+pub(crate) fn where_clauses(cx: &DocContext<'_>, clauses: Vec<WP>) -> ThinVec<WP> {
// First, partition the where clause into its separate components.
//
// We use `FxIndexMap` so that the insertion order is preserved to prevent messing up to
let Some((bounds, _)) = tybounds.get_mut(ty) else { return true };
let bound_params = bound_params
.into_iter()
- .map(|param| clean::GenericParamDef {
- name: param.0,
- kind: clean::GenericParamDefKind::Lifetime { outlives: Vec::new() },
- })
+ .map(|param| clean::GenericParamDef::lifetime(param.0))
.collect();
merge_bounds(cx, bounds, bound_params, trait_did, name, rhs)
});
// And finally, let's reassemble everything
- let mut clauses = Vec::new();
+ let mut clauses = ThinVec::with_capacity(lifetimes.len() + tybounds.len() + equalities.len());
clauses.extend(
lifetimes.into_iter().map(|(lt, bounds)| WP::RegionPredicate { lifetime: lt, bounds }),
);
let last = trait_ref.trait_.segments.last_mut().expect("segments were empty");
trait_ref.generic_params.append(&mut bound_params);
- // Since the parameters (probably) originate from `tcx.collect_*_late_bound_regions` which
- // returns a hash set, sort them alphabetically to guarantee a stable and deterministic
- // output (and to fully deduplicate them).
+ // Sort parameters (likely) originating from a hashset alphabetically to
+ // produce predictable output (and to allow for full deduplication).
trait_ref.generic_params.sort_unstable_by(|p, q| p.name.as_str().cmp(q.name.as_str()));
trait_ref.generic_params.dedup_by_key(|p| p.name);
use rustc_hir_analysis::check::intrinsic::intrinsic_operation_unsafety;
use rustc_index::vec::IndexVec;
use rustc_middle::ty::fast_reject::SimplifiedType;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, DefIdTree, TyCtxt, Visibility};
use rustc_session::Session;
use rustc_span::hygiene::MacroKind;
use rustc_span::source_map::DUMMY_SP;
use rustc_target::spec::abi::Abi;
use crate::clean::cfg::Cfg;
-use crate::clean::clean_visibility;
use crate::clean::external_path;
use crate::clean::inline::{self, print_inlined_const};
use crate::clean::utils::{is_literal_expr, print_const_expr, print_evaluated_const};
Array, BareFunction, BorrowedRef, DynTrait, Generic, ImplTrait, Infer, Primitive, QPath,
RawPointer, Slice, Tuple,
};
-pub(crate) use self::Visibility::{Inherited, Public};
#[cfg(test)]
mod tests;
let item = tcx.hir().item(id);
match item.kind {
hir::ItemKind::Mod(_) => {
- as_keyword(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
+ as_keyword(Res::Def(DefKind::Mod, id.owner_id.to_def_id()))
}
hir::ItemKind::Use(path, hir::UseKind::Single)
- if tcx.visibility(id.def_id).is_public() =>
+ if tcx.visibility(id.owner_id).is_public() =>
{
as_keyword(path.res.expect_non_local())
- .map(|(_, prim)| (id.def_id.to_def_id(), prim))
+ .map(|(_, prim)| (id.owner_id.to_def_id(), prim))
}
_ => None,
}
let item = tcx.hir().item(id);
match item.kind {
hir::ItemKind::Mod(_) => {
- as_primitive(Res::Def(DefKind::Mod, id.def_id.to_def_id()))
+ as_primitive(Res::Def(DefKind::Mod, id.owner_id.to_def_id()))
}
hir::ItemKind::Use(path, hir::UseKind::Single)
- if tcx.visibility(id.def_id).is_public() =>
+ if tcx.visibility(id.owner_id).is_public() =>
{
as_primitive(path.res.expect_non_local()).map(|(_, prim)| {
// Pretend the primitive is local.
- (id.def_id.to_def_id(), prim)
+ (id.owner_id.to_def_id(), prim)
})
}
_ => None,
/// Optional because not every item has a name, e.g. impls.
pub(crate) name: Option<Symbol>,
pub(crate) attrs: Box<Attributes>,
- pub(crate) visibility: Visibility,
/// Information about this item that is specific to what kind of item it is.
/// E.g., struct vs enum vs function.
pub(crate) kind: Box<ItemKind>,
pub(crate) item_id: ItemId,
-
+ /// This is the `DefId` of the `use` statement if the item was inlined.
+ pub(crate) inline_stmt_id: Option<DefId>,
pub(crate) cfg: Option<Arc<Cfg>>,
}
let alternate = f.alternate();
// hand-picked fields that don't bloat the logs too much
let mut fmt = f.debug_struct("Item");
- fmt.field("name", &self.name)
- .field("visibility", &self.visibility)
- .field("item_id", &self.item_id);
+ fmt.field("name", &self.name).field("item_id", &self.item_id);
// allow printing the full item if someone really wants to
if alternate {
fmt.field("attrs", &self.attrs).field("kind", &self.kind).field("cfg", &self.cfg);
))
}
+fn is_field_vis_inherited(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+ let parent = tcx.parent(def_id);
+ match tcx.def_kind(parent) {
+ DefKind::Struct | DefKind::Union => false,
+ DefKind::Variant => true,
+ parent_kind => panic!("unexpected parent kind: {:?}", parent_kind),
+ }
+}
+
impl Item {
pub(crate) fn stability<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<Stability> {
self.item_id.as_def_id().and_then(|did| tcx.lookup_stability(did))
name,
kind,
Box::new(Attributes::from_ast(ast_attrs)),
- cx,
ast_attrs.cfg(cx.tcx, &cx.cache.hidden_cfg),
)
}
name: Option<Symbol>,
kind: ItemKind,
attrs: Box<Attributes>,
- cx: &mut DocContext<'_>,
cfg: Option<Arc<Cfg>>,
) -> Item {
trace!("name={:?}, def_id={:?} cfg={:?}", name, def_id, cfg);
- // Primitives and Keywords are written in the source code as private modules.
- // The modules need to be private so that nobody actually uses them, but the
- // keywords and primitives that they are documenting are public.
- let visibility = if matches!(&kind, ItemKind::KeywordItem | ItemKind::PrimitiveItem(..)) {
- Visibility::Public
- } else {
- clean_visibility(cx.tcx.visibility(def_id))
- };
-
- Item { item_id: def_id.into(), kind: Box::new(kind), name, attrs, visibility, cfg }
+ Item {
+ item_id: def_id.into(),
+ kind: Box::new(kind),
+ name,
+ attrs,
+ cfg,
+ inline_stmt_id: None,
+ }
}
/// Finds all `doc` attributes as NameValues and returns their corresponding values, joined
asyncness: hir::IsAsync::NotAsync,
}
}
- ItemKind::FunctionItem(_) | ItemKind::MethodItem(_, _) => {
+ ItemKind::FunctionItem(_) | ItemKind::MethodItem(_, _) | ItemKind::TyMethodItem(_) => {
let def_id = self.item_id.as_def_id().unwrap();
build_fn_header(def_id, tcx, tcx.asyncness(def_id))
}
- ItemKind::TyMethodItem(_) => {
- build_fn_header(self.item_id.as_def_id().unwrap(), tcx, hir::IsAsync::NotAsync)
- }
_ => return None,
};
Some(header)
}
+
+ /// Returns the visibility of the current item. If the visibility is "inherited", then `None`
+ /// is returned.
+ pub(crate) fn visibility(&self, tcx: TyCtxt<'_>) -> Option<Visibility<DefId>> {
+ let def_id = match self.item_id {
+ // Anything but DefId *shouldn't* matter, but return a reasonable value anyway.
+ ItemId::Auto { .. } | ItemId::Blanket { .. } => return None,
+ // Primitives and Keywords are written in the source code as private modules.
+ // The modules need to be private so that nobody actually uses them, but the
+ // keywords and primitives that they are documenting are public.
+ ItemId::Primitive(..) => return Some(Visibility::Public),
+ ItemId::DefId(def_id) => def_id,
+ };
+
+ match *self.kind {
+ // Explication on `ItemId::Primitive` just above.
+ ItemKind::KeywordItem | ItemKind::PrimitiveItem(_) => return Some(Visibility::Public),
+ // Variant fields inherit their enum's visibility.
+ StructFieldItem(..) if is_field_vis_inherited(tcx, def_id) => {
+ return None;
+ }
+ // Variants always inherit visibility
+ VariantItem(..) => return None,
+ // Trait items inherit the trait's visibility
+ AssocConstItem(..) | TyAssocConstItem(..) | AssocTypeItem(..) | TyAssocTypeItem(..)
+ | TyMethodItem(..) | MethodItem(..) => {
+ let assoc_item = tcx.associated_item(def_id);
+ let is_trait_item = match assoc_item.container {
+ ty::TraitContainer => true,
+ ty::ImplContainer => {
+ // Trait impl items always inherit the impl's visibility --
+ // we don't want to show `pub`.
+ tcx.impl_trait_ref(tcx.parent(assoc_item.def_id)).is_some()
+ }
+ };
+ if is_trait_item {
+ return None;
+ }
+ }
+ _ => {}
+ }
+ let def_id = match self.inline_stmt_id {
+ Some(inlined) => inlined,
+ None => def_id,
+ };
+ Some(tcx.visibility(def_id))
+ }
}
#[derive(Clone, Debug)]
/// A required associated type in a trait declaration.
///
/// The bounds may be non-empty if there is a `where` clause.
- TyAssocTypeItem(Box<Generics>, Vec<GenericBound>),
+ TyAssocTypeItem(Generics, Vec<GenericBound>),
/// An associated type in a trait impl or a provided one in a trait declaration.
AssocTypeItem(Box<Typedef>, Vec<GenericBound>),
/// An item that has been stripped by a rustdoc pass
}
impl GenericParamDef {
+ pub(crate) fn lifetime(name: Symbol) -> Self {
+ Self { name, kind: GenericParamDefKind::Lifetime { outlives: Vec::new() } }
+ }
+
pub(crate) fn is_synthetic_type_param(&self) -> bool {
match self.kind {
GenericParamDefKind::Lifetime { .. } | GenericParamDefKind::Const { .. } => false,
// maybe use a Generic enum and use Vec<Generic>?
#[derive(Clone, Debug, Default)]
pub(crate) struct Generics {
- pub(crate) params: Vec<GenericParamDef>,
- pub(crate) where_predicates: Vec<WherePredicate>,
+ pub(crate) params: ThinVec<GenericParamDef>,
+ pub(crate) where_predicates: ThinVec<WherePredicate>,
}
impl Generics {
/// An array type.
///
/// The `String` field is a stringified version of the array's length parameter.
- Array(Box<Type>, String),
+ Array(Box<Type>, Box<str>),
/// A raw pointer type: `*const i32`, `*mut i32`
RawPointer(Mutability, Box<Type>),
/// A reference type: `&i32`, `&'a mut Foo`
}
}
-#[derive(Copy, Clone, Debug)]
-pub(crate) enum Visibility {
- /// `pub`
- Public,
- /// Visibility inherited from parent.
- ///
- /// For example, this is the visibility of private items and of enum variants.
- Inherited,
- /// `pub(crate)`, `pub(super)`, or `pub(in path::to::somewhere)`
- Restricted(DefId),
-}
-
-impl Visibility {
- pub(crate) fn is_public(&self) -> bool {
- matches!(self, Visibility::Public)
- }
-}
-
#[derive(Clone, Debug)]
pub(crate) struct Struct {
pub(crate) struct_type: CtorKind,
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub(crate) struct Path {
pub(crate) res: Res,
- pub(crate) segments: Vec<PathSegment>,
+ pub(crate) segments: ThinVec<PathSegment>,
}
impl Path {
///
/// Note that `ty::Const` includes generic parameters, and may not always be uniquely identified
/// by a DefId. So this field must be different from `Extern`.
- TyConst { expr: String },
+ TyConst { expr: Box<str> },
/// A constant (expression) that's not an item or associated item. These are usually found
/// nested inside types (e.g., array lengths) or expressions (e.g., repeat counts), and also
/// used to define explicit discriminant values for enum variants.
impl ConstantKind {
pub(crate) fn expr(&self, tcx: TyCtxt<'_>) -> String {
match *self {
- ConstantKind::TyConst { ref expr } => expr.clone(),
+ ConstantKind::TyConst { ref expr } => expr.to_string(),
ConstantKind::Extern { def_id } => print_inlined_const(tcx, def_id),
ConstantKind::Local { body, .. } | ConstantKind::Anonymous { body } => {
print_const_expr(tcx, body)
// tidy-alphabetical-start
static_assert_size!(Crate, 72); // frequently moved by-value
static_assert_size!(DocFragment, 32);
- static_assert_size!(GenericArg, 48);
+ static_assert_size!(GenericArg, 32);
static_assert_size!(GenericArgs, 32);
static_assert_size!(GenericParamDef, 56);
+ static_assert_size!(Generics, 16);
static_assert_size!(Item, 56);
- static_assert_size!(ItemKind, 88);
+ static_assert_size!(ItemKind, 64);
static_assert_size!(PathSegment, 40);
- static_assert_size!(Type, 48);
+ static_assert_size!(Type, 32);
// tidy-alphabetical-end
}
use crate::clean::{
clean_doc_module, clean_middle_const, clean_middle_region, clean_middle_ty, inline, Crate,
ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item, ItemKind, Lifetime, Path,
- PathSegment, Primitive, PrimitiveType, Type, TypeBinding, Visibility,
+ PathSegment, Primitive, PrimitiveType, Term, Type, TypeBinding, TypeBindingKind,
};
use crate::core::DocContext;
-use crate::formats::item_type::ItemType;
-use crate::visit_lib::LibEmbargoVisitor;
+use crate::html::format::visibility_to_src_with_space;
use rustc_ast as ast;
use rustc_ast::tokenstream::TokenTree;
use rustc_span::symbol::{kw, sym, Symbol};
use std::fmt::Write as _;
use std::mem;
-use thin_vec::ThinVec;
+use thin_vec::{thin_vec, ThinVec};
#[cfg(test)]
mod tests;
for &cnum in cx.tcx.crates(()) {
// Analyze doc-reachability for extern items
- LibEmbargoVisitor::new(cx).visit_lib(cnum);
+ crate::visit_lib::lib_embargo_visit_item(cx, cnum.as_def_id());
}
// Clean the crate, translating the entire librustc_ast AST to one that is
ty::Tuple(tys) => tys.iter().map(|t| clean_middle_ty(t, cx, None)).collect::<Vec<_>>().into(),
_ => return GenericArgs::AngleBracketed { args: args.into(), bindings },
};
- let output = None;
- // FIXME(#20299) return type comes from a projection now
- // match types[1].kind {
- // ty::Tuple(ref v) if v.is_empty() => None, // -> ()
- // _ => Some(types[1].clean(cx))
- // };
+ let output = bindings.into_iter().next().and_then(|binding| match binding.kind {
+ TypeBindingKind::Equality { term: Term::Type(ty) } if ty != Type::Tuple(Vec::new()) => {
+ Some(Box::new(ty))
+ }
+ _ => None,
+ });
GenericArgs::Parenthesized { inputs, output }
} else {
GenericArgs::AngleBracketed { args: args.into(), bindings: bindings.into() }
let name = cx.tcx.item_name(did);
Path {
res: Res::Def(def_kind, did),
- segments: vec![PathSegment {
+ segments: thin_vec![PathSegment {
name,
args: external_generic_args(cx, did, has_self, bindings, substs),
}],
s
}
- _ => {
- let mut s = n.to_string();
- // array lengths are obviously usize
- if s.ends_with("_usize") {
- let n = s.len() - "_usize".len();
- s.truncate(n);
- if s.ends_with(": ") {
- let n = s.len() - ": ".len();
- s.truncate(n);
- }
- }
- s
+ // array lengths are obviously usize
+ ty::ConstKind::Value(ty::ValTree::Leaf(scalar))
+ if *n.ty().kind() == ty::Uint(ty::UintTy::Usize) =>
+ {
+ scalar.to_string()
}
+ _ => n.to_string(),
}
}
return did;
}
inline::record_extern_fqn(cx, did, kind);
- if let ItemType::Trait = kind {
- inline::record_extern_trait(cx, did);
- }
did
}
name: Symbol,
def: &ast::MacroDef,
def_id: DefId,
- vis: Visibility,
+ vis: ty::Visibility<DefId>,
) -> String {
let tts: Vec<_> = def.body.inner_tokens().into_trees().collect();
// Extract the spans of all matchers. They represent the "interface" of the macro.
if matchers.len() <= 1 {
format!(
"{}macro {}{} {{\n ...\n}}",
- vis.to_src_with_space(cx.tcx, def_id),
+ visibility_to_src_with_space(Some(vis), cx.tcx, def_id),
name,
matchers.map(|matcher| render_macro_matcher(cx.tcx, matcher)).collect::<String>(),
)
} else {
format!(
"{}macro {} {{\n{}}}",
- vis.to_src_with_space(cx.tcx, def_id),
+ visibility_to_src_with_space(Some(vis), cx.tcx, def_id),
name,
render_macro_arms(cx.tcx, matchers, ","),
)
pub(crate) default_settings: FxHashMap<String, String>,
/// If present, suffix added to CSS/JavaScript files when referencing them in generated pages.
pub(crate) resource_suffix: String,
- /// Whether to run the static CSS/JavaScript through a minifier when outputting them. `true` by
- /// default.
- pub(crate) enable_minification: bool,
/// Whether to create an index page in the root of the output directory. If this is true but
/// `enable_index_page` is None, generate a static listing of crates instead.
pub(crate) enable_index_page: bool,
let to_check = matches.opt_strs("check-theme");
if !to_check.is_empty() {
- let paths = match theme::load_css_paths(static_files::themes::LIGHT) {
+ let paths = match theme::load_css_paths(
+ std::str::from_utf8(static_files::STATIC_FILES.theme_light_css.bytes).unwrap(),
+ ) {
Ok(p) => p,
Err(e) => {
diag.struct_err(&e.to_string()).emit();
let mut themes = Vec::new();
if matches.opt_present("theme") {
- let paths = match theme::load_css_paths(static_files::themes::LIGHT) {
+ let paths = match theme::load_css_paths(
+ std::str::from_utf8(static_files::STATIC_FILES.theme_light_css.bytes).unwrap(),
+ ) {
Ok(p) => p,
Err(e) => {
diag.struct_err(&e.to_string()).emit();
ModuleSorting::Alphabetical
};
let resource_suffix = matches.opt_str("resource-suffix").unwrap_or_default();
- let enable_minification = !matches.opt_present("disable-minification");
let markdown_no_toc = matches.opt_present("markdown-no-toc");
let markdown_css = matches.opt_strs("markdown-css");
let markdown_playground_url = matches.opt_str("markdown-playground-url");
extern_html_root_takes_precedence,
default_settings,
resource_suffix,
- enable_minification,
enable_index_page,
index_page,
static_root_path,
use rustc_ast::NodeId;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::{self, Lrc};
+use rustc_data_structures::unord::UnordSet;
use rustc_errors::emitter::{Emitter, EmitterWriter};
use rustc_errors::json::JsonEmitter;
use rustc_feature::UnstableFeatures;
unstable_opts.teach,
diagnostic_width,
false,
+ unstable_opts.track_diagnostics,
)
.ui_testing(unstable_opts.ui_testing),
)
json_rendered,
diagnostic_width,
false,
+ unstable_opts.track_diagnostics,
)
.ui_testing(unstable_opts.ui_testing),
)
providers.typeck_item_bodies = |_, _| {};
// hack so that `used_trait_imports` won't try to call typeck
providers.used_trait_imports = |_, _| {
- static EMPTY_SET: LazyLock<FxHashSet<LocalDefId>> =
- LazyLock::new(FxHashSet::default);
+ static EMPTY_SET: LazyLock<UnordSet<LocalDefId>> = LazyLock::new(UnordSet::default);
&EMPTY_SET
};
// In case typeck does end up being called, don't ICE in case there were name resolution errors
let auto_traits =
tcx.all_traits().filter(|&trait_def_id| tcx.trait_is_auto(trait_def_id)).collect();
- let access_levels = tcx.privacy_access_levels(()).map_id(Into::into);
let mut ctxt = DocContext {
tcx,
impl_trait_bounds: Default::default(),
generated_synthetics: Default::default(),
auto_traits,
- cache: Cache::new(access_levels, render_options.document_private),
+ cache: Cache::new(render_options.document_private),
inlined: FxHashSet::default(),
output_format,
render_options,
false,
Some(80),
false,
+ false,
)
.supports_color();
false,
None,
false,
+ false,
);
// FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser
false,
None,
false,
+ false,
);
let handler = Handler::with_emitter(false, None, Box::new(emitter));
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir::def_id::{CrateNum, DefId};
-use rustc_middle::middle::privacy::AccessLevels;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::Symbol;
use crate::html::markdown::short_markdown_summary;
use crate::html::render::search_index::get_function_type_for_search;
use crate::html::render::IndexItem;
+use crate::visit_lib::RustdocEffectiveVisibilities;
/// This cache is used to store information about the [`clean::Crate`] being
/// rendered in order to provide more useful documentation. This contains
// Note that external items for which `doc(hidden)` applies to are shown as
// non-reachable while local items aren't. This is because we're reusing
- // the access levels from the privacy check pass.
- pub(crate) access_levels: AccessLevels<DefId>,
+ // the effective visibilities from the privacy check pass.
+ pub(crate) effective_visibilities: RustdocEffectiveVisibilities,
/// The version of the crate being documented, if given from the `--crate-version` flag.
pub(crate) crate_version: Option<String>,
}
impl Cache {
- pub(crate) fn new(access_levels: AccessLevels<DefId>, document_private: bool) -> Self {
- Cache { access_levels, document_private, ..Cache::default() }
+ pub(crate) fn new(document_private: bool) -> Self {
+ Cache { document_private, ..Cache::default() }
}
/// Populates the `Cache` with more data. The returned `Crate` will be missing some data that was
let desc = item.doc_value().map_or_else(String::new, |x| {
short_markdown_summary(x.as_str(), &item.link_names(self.cache))
});
- self.cache.search_index.push(IndexItem {
- ty: item.type_(),
- name: s.to_string(),
- path: join_with_double_colon(path),
- desc,
- parent,
- parent_idx: None,
- search_type: get_function_type_for_search(
- &item,
- self.tcx,
- clean_impl_generics(self.cache.parent_stack.last()).as_ref(),
- self.cache,
- ),
- aliases: item.attrs.get_doc_aliases(),
- });
+ let ty = item.type_();
+ let name = s.to_string();
+ if ty != ItemType::StructField || u16::from_str_radix(&name, 10).is_err() {
+ // In case this is a field from a tuple struct, we don't add it into
+ // the search index because its name is something like "0", which is
+ // not useful for rustdoc search.
+ self.cache.search_index.push(IndexItem {
+ ty,
+ name,
+ path: join_with_double_colon(path),
+ desc,
+ parent,
+ parent_idx: None,
+ search_type: get_function_type_for_search(
+ &item,
+ self.tcx,
+ clean_impl_generics(self.cache.parent_stack.last()).as_ref(),
+ self.cache,
+ ),
+ aliases: item.attrs.get_doc_aliases(),
+ });
+ }
}
}
(Some(parent), None) if is_inherent_impl_item => {
// paths map if there was already an entry present and we're
// not a public item.
if !self.cache.paths.contains_key(&item.item_id.expect_def_id())
- || self.cache.access_levels.is_public(item.item_id.expect_def_id())
+ || self
+ .cache
+ .effective_visibilities
+ .is_directly_public(self.tcx, item.item_id.expect_def_id())
{
self.cache.paths.insert(
item.item_id.expect_def_id(),
}
if !did.is_local()
- && !cache.access_levels.is_public(did)
+ && !cache.effective_visibilities.is_directly_public(tcx, did)
&& !cache.document_private
&& !cache.primitive_locations.values().any(|&id| id == did)
{
) -> impl fmt::Display + 'a + Captures<'tcx> {
display_fn(move |f| {
for (i, input) in self.values.iter().enumerate() {
- if !input.name.is_empty() {
- write!(f, "{}: ", input.name)?;
- }
+ write!(f, "{}: ", input.name)?;
+
if f.alternate() {
write!(f, "{:#}", input.type_.print(cx))?;
} else {
args.push_str("const ");
args_plain.push_str("const ");
}
- if !input.name.is_empty() {
- write!(args, "{}: ", input.name);
- write!(args_plain, "{}: ", input.name);
- }
+ write!(args, "{}: ", input.name);
+ write!(args_plain, "{}: ", input.name);
if f.alternate() {
write!(args, "{:#}", input.type_.print(cx));
}
}
-impl clean::Visibility {
- pub(crate) fn print_with_space<'a, 'tcx: 'a>(
- self,
- item_did: ItemId,
- cx: &'a Context<'tcx>,
- ) -> impl fmt::Display + 'a + Captures<'tcx> {
- use std::fmt::Write as _;
-
- let to_print: Cow<'static, str> = match self {
- clean::Public => "pub ".into(),
- clean::Inherited => "".into(),
- clean::Visibility::Restricted(vis_did) => {
- // FIXME(camelid): This may not work correctly if `item_did` is a module.
- // However, rustdoc currently never displays a module's
- // visibility, so it shouldn't matter.
- let parent_module = find_nearest_parent_module(cx.tcx(), item_did.expect_def_id());
-
- if vis_did.is_crate_root() {
- "pub(crate) ".into()
- } else if parent_module == Some(vis_did) {
- // `pub(in foo)` where `foo` is the parent module
- // is the same as no visibility modifier
- "".into()
- } else if parent_module
- .and_then(|parent| find_nearest_parent_module(cx.tcx(), parent))
- == Some(vis_did)
- {
- "pub(super) ".into()
- } else {
- let path = cx.tcx().def_path(vis_did);
- debug!("path={:?}", path);
- // modified from `resolved_path()` to work with `DefPathData`
- let last_name = path.data.last().unwrap().data.get_opt_name().unwrap();
- let anchor = anchor(vis_did, last_name, cx).to_string();
-
- let mut s = "pub(in ".to_owned();
- for seg in &path.data[..path.data.len() - 1] {
- let _ = write!(s, "{}::", seg.data.get_opt_name().unwrap());
- }
- let _ = write!(s, "{}) ", anchor);
- s.into()
+pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>(
+ visibility: Option<ty::Visibility<DefId>>,
+ item_did: ItemId,
+ cx: &'a Context<'tcx>,
+) -> impl fmt::Display + 'a + Captures<'tcx> {
+ use std::fmt::Write as _;
+
+ let to_print: Cow<'static, str> = match visibility {
+ None => "".into(),
+ Some(ty::Visibility::Public) => "pub ".into(),
+ Some(ty::Visibility::Restricted(vis_did)) => {
+ // FIXME(camelid): This may not work correctly if `item_did` is a module.
+ // However, rustdoc currently never displays a module's
+ // visibility, so it shouldn't matter.
+ let parent_module = find_nearest_parent_module(cx.tcx(), item_did.expect_def_id());
+
+ if vis_did.is_crate_root() {
+ "pub(crate) ".into()
+ } else if parent_module == Some(vis_did) {
+ // `pub(in foo)` where `foo` is the parent module
+ // is the same as no visibility modifier
+ "".into()
+ } else if parent_module.and_then(|parent| find_nearest_parent_module(cx.tcx(), parent))
+ == Some(vis_did)
+ {
+ "pub(super) ".into()
+ } else {
+ let path = cx.tcx().def_path(vis_did);
+ debug!("path={:?}", path);
+ // modified from `resolved_path()` to work with `DefPathData`
+ let last_name = path.data.last().unwrap().data.get_opt_name().unwrap();
+ let anchor = anchor(vis_did, last_name, cx).to_string();
+
+ let mut s = "pub(in ".to_owned();
+ for seg in &path.data[..path.data.len() - 1] {
+ let _ = write!(s, "{}::", seg.data.get_opt_name().unwrap());
}
+ let _ = write!(s, "{}) ", anchor);
+ s.into()
}
- };
- display_fn(move |f| write!(f, "{}", to_print))
- }
+ }
+ };
+ display_fn(move |f| write!(f, "{}", to_print))
+}
- /// This function is the same as print_with_space, except that it renders no links.
- /// It's used for macros' rendered source view, which is syntax highlighted and cannot have
- /// any HTML in it.
- pub(crate) fn to_src_with_space<'a, 'tcx: 'a>(
- self,
- tcx: TyCtxt<'tcx>,
- item_did: DefId,
- ) -> impl fmt::Display + 'a + Captures<'tcx> {
- let to_print = match self {
- clean::Public => "pub ".to_owned(),
- clean::Inherited => String::new(),
- clean::Visibility::Restricted(vis_did) => {
- // FIXME(camelid): This may not work correctly if `item_did` is a module.
- // However, rustdoc currently never displays a module's
- // visibility, so it shouldn't matter.
- let parent_module = find_nearest_parent_module(tcx, item_did);
-
- if vis_did.is_crate_root() {
- "pub(crate) ".to_owned()
- } else if parent_module == Some(vis_did) {
- // `pub(in foo)` where `foo` is the parent module
- // is the same as no visibility modifier
- String::new()
- } else if parent_module.and_then(|parent| find_nearest_parent_module(tcx, parent))
- == Some(vis_did)
- {
- "pub(super) ".to_owned()
- } else {
- format!("pub(in {}) ", tcx.def_path_str(vis_did))
- }
+/// This function is the same as print_with_space, except that it renders no links.
+/// It's used for macros' rendered source view, which is syntax highlighted and cannot have
+/// any HTML in it.
+pub(crate) fn visibility_to_src_with_space<'a, 'tcx: 'a>(
+ visibility: Option<ty::Visibility<DefId>>,
+ tcx: TyCtxt<'tcx>,
+ item_did: DefId,
+) -> impl fmt::Display + 'a + Captures<'tcx> {
+ let to_print = match visibility {
+ None => String::new(),
+ Some(ty::Visibility::Public) => "pub ".to_owned(),
+ Some(ty::Visibility::Restricted(vis_did)) => {
+ // FIXME(camelid): This may not work correctly if `item_did` is a module.
+ // However, rustdoc currently never displays a module's
+ // visibility, so it shouldn't matter.
+ let parent_module = find_nearest_parent_module(tcx, item_did);
+
+ if vis_did.is_crate_root() {
+ "pub(crate) ".to_owned()
+ } else if parent_module == Some(vis_did) {
+ // `pub(in foo)` where `foo` is the parent module
+ // is the same as no visibility modifier
+ String::new()
+ } else if parent_module.and_then(|parent| find_nearest_parent_module(tcx, parent))
+ == Some(vis_did)
+ {
+ "pub(super) ".to_owned()
+ } else {
+ format!("pub(in {}) ", tcx.def_path_str(vis_did))
}
- };
- display_fn(move |f| f.write_str(&to_print))
- }
+ }
+ };
+ display_fn(move |f| f.write_str(&to_print))
}
pub(crate) trait PrintWithSpace {
line_numbers: Buffer,
href_context: HrefContext<'_, '_, '_>,
decoration_info: DecorationInfo,
+ extra: Option<&str>,
) {
write_header(out, "", Some(line_numbers), Tooltip::None);
+ if let Some(extra) = extra {
+ out.push_str(extra);
+ }
write_code(out, src, Some(href_context), Some(decoration_info));
write_footer(out, None);
}
match self {
Class::Comment => "comment",
Class::DocComment => "doccomment",
- Class::Attribute => "attribute",
+ Class::Attribute => "attr",
Class::KeyWord => "kw",
Class::RefKeyWord => "kw-2",
Class::Self_(_) => "self",
.kw { color: #8959A8; }
.kw-2, .prelude-ty { color: #4271AE; }
.number, .string { color: #718C00; }
-.self, .bool-val, .prelude-val, .attribute, .attribute .ident { color: #C82829; }
+.self, .bool-val, .prelude-val, .attr, .attr .ident { color: #C82829; }
.macro, .macro-nonterminal { color: #3E999F; }
.lifetime { color: #B76514; }
.question-mark { color: #ff9011; }
</style>
-<pre><code><span class="attribute">#![crate_type = <span class="string">"lib"</span>]
+<pre><code><span class="attr">#![crate_type = <span class="string">"lib"</span>]
</span><span class="kw">use </span>std::path::{Path, PathBuf};
-<span class="attribute">#[cfg(target_os = <span class="string">"linux"</span>)]
+<span class="attr">#[cfg(target_os = <span class="string">"linux"</span>)]
#[cfg(target_os = <span class="string">"windows"</span>)]
</span><span class="kw">fn </span>main() -> () {
<span class="kw">let </span>foo = <span class="bool-val">true </span>&& <span class="bool-val">false </span>|| <span class="bool-val">true</span>;
<span class="macro">mac!</span>(foo, <span class="kw-2">&mut </span>bar);
<span class="macro">assert!</span>(<span class="self">self</span>.length < N && index <= <span class="self">self</span>.length);
::std::env::var(<span class="string">"gateau"</span>).is_ok();
- <span class="attribute">#[rustfmt::skip]
+ <span class="attr">#[rustfmt::skip]
</span><span class="kw">let </span>s:std::path::PathBuf = std::path::PathBuf::new();
<span class="kw">let </span><span class="kw-2">mut </span>s = String::new();
.kw { color: #8959A8; }
.kw-2, .prelude-ty { color: #4271AE; }
.number, .string { color: #718C00; }
-.self, .bool-val, .prelude-val, .attribute, .attribute .ident { color: #C82829; }
+.self, .bool-val, .prelude-val, .attr, .attr .ident { color: #C82829; }
.macro, .macro-nonterminal { color: #3E999F; }
.lifetime { color: #B76514; }
.question-mark { color: #ff9011; }
use rustc_data_structures::fx::FxHashMap;
-use crate::error::Error;
use crate::externalfiles::ExternalHtml;
use crate::html::format::{Buffer, Print};
use crate::html::render::{ensure_trailing_slash, StylePath};
use askama::Template;
+use super::static_files::{StaticFiles, STATIC_FILES};
+
#[derive(Clone)]
pub(crate) struct Layout {
pub(crate) logo: String,
}
impl<'a> Page<'a> {
- pub(crate) fn get_static_root_path(&self) -> &str {
- self.static_root_path.unwrap_or(self.root_path)
+ pub(crate) fn get_static_root_path(&self) -> String {
+ match self.static_root_path {
+ Some(s) => s.to_string(),
+ None => format!("{}static.files/", self.root_path),
+ }
}
}
#[derive(Template)]
#[template(path = "page.html")]
struct PageLayout<'a> {
- static_root_path: &'a str,
+ static_root_path: String,
page: &'a Page<'a>,
layout: &'a Layout,
+
+ files: &'static StaticFiles,
+
themes: Vec<String>,
sidebar: String,
content: String,
) -> String {
let static_root_path = page.get_static_root_path();
let krate_with_trailing_slash = ensure_trailing_slash(&layout.krate).to_string();
- let mut themes: Vec<String> = style_files
- .iter()
- .map(StylePath::basename)
- .collect::<Result<_, Error>>()
- .unwrap_or_default();
+ let mut themes: Vec<String> = style_files.iter().map(|s| s.basename().unwrap()).collect();
themes.sort();
+
let rustdoc_version = rustc_interface::util::version_str().unwrap_or("unknown version");
let content = Buffer::html().to_display(t); // Note: This must happen before making the sidebar.
let sidebar = Buffer::html().to_display(sidebar);
static_root_path,
page,
layout,
+ files: &STATIC_FILES,
themes,
sidebar,
content,
use crate::html::format::{join_with_double_colon, Buffer};
use crate::html::markdown::{self, plain_text_summary, ErrorCodes, IdMap};
use crate::html::url_parts_builder::UrlPartsBuilder;
-use crate::html::{layout, sources};
+use crate::html::{layout, sources, static_files};
use crate::scrape_examples::AllCallLocations;
use crate::try_err;
);
let (sender, receiver) = channel();
- let mut scx = SharedContext {
+ let scx = SharedContext {
tcx,
src_root,
local_sources,
call_locations,
};
- // Add the default themes to the `Vec` of stylepaths
- //
- // Note that these must be added before `sources::render` is called
- // so that the resulting source pages are styled
- //
- // `light.css` is not disabled because it is the stylesheet that stays loaded
- // by the browser as the theme stylesheet. The theme system (hackily) works by
- // changing the href to this stylesheet. All other themes are disabled to
- // prevent rule conflicts
- scx.style_files.push(StylePath { path: PathBuf::from("light.css") });
- scx.style_files.push(StylePath { path: PathBuf::from("dark.css") });
- scx.style_files.push(StylePath { path: PathBuf::from("ayu.css") });
-
let dst = output;
scx.ensure_dir(&dst)?;
</section>\
</noscript>\
<link rel=\"stylesheet\" type=\"text/css\" \
- href=\"{root_path}settings{suffix}.css\">\
- <script defer src=\"{root_path}settings{suffix}.js\"></script>",
- root_path = page.static_root_path.unwrap_or(""),
- suffix = page.resource_suffix,
+ href=\"{static_root_path}{settings_css}\">\
+ <script defer src=\"{static_root_path}{settings_js}\"></script>",
+ static_root_path = page.get_static_root_path(),
+ settings_css = static_files::STATIC_FILES.settings_css,
+ settings_js = static_files::STATIC_FILES.settings_js,
)
},
&shared.style_files,
use crate::html::escape::Escape;
use crate::html::format::{
href, join_with_double_colon, print_abi_with_space, print_constness_with_space,
- print_default_space, print_generic_bounds, print_where_clause, Buffer, Ending, HrefError,
- PrintWithSpace,
+ print_default_space, print_generic_bounds, print_where_clause, visibility_print_with_space,
+ Buffer, Ending, HrefError, PrintWithSpace,
};
use crate::html::highlight;
use crate::html::markdown::{
extra: &str,
cx: &Context<'_>,
) {
+ let tcx = cx.tcx();
write!(
w,
"{extra}{vis}const <a{href} class=\"constant\">{name}</a>: {ty}",
extra = extra,
- vis = it.visibility.print_with_space(it.item_id, cx),
+ vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
href = assoc_href_attr(it, link, cx),
name = it.name.as_ref().unwrap(),
ty = ty.print(cx),
// This hurts readability in this context especially when more complex expressions
// are involved and it doesn't add much of value.
// Find a way to print constants here without all that jazz.
- write!(w, "{}", Escape(&default.value(cx.tcx()).unwrap_or_else(|| default.expr(cx.tcx()))));
+ write!(w, "{}", Escape(&default.value(tcx).unwrap_or_else(|| default.expr(tcx))));
}
}
cx: &Context<'_>,
render_mode: RenderMode,
) {
- let header = meth.fn_header(cx.tcx()).expect("Trying to get header from a non-function item");
+ let tcx = cx.tcx();
+ let header = meth.fn_header(tcx).expect("Trying to get header from a non-function item");
let name = meth.name.as_ref().unwrap();
- let vis = meth.visibility.print_with_space(meth.item_id, cx).to_string();
+ let vis = visibility_print_with_space(meth.visibility(tcx), meth.item_id, cx).to_string();
// FIXME: Once https://github.com/rust-lang/rust/issues/67792 is implemented, we can remove
// this condition.
let constness = match render_mode {
RenderMode::Normal => {
- print_constness_with_space(&header.constness, meth.const_stability(cx.tcx()))
+ print_constness_with_space(&header.constness, meth.const_stability(tcx))
}
RenderMode::ForDeref { .. } => "",
};
write!(w, r#"<span class="prev">≺</span> <span class="next">≻</span>"#);
}
- if needs_expansion {
- write!(w, r#"<span class="expand">↕</span>"#);
- }
-
// Look for the example file in the source map if it exists, otherwise return a dummy span
let file_span = (|| {
let source_map = tcx.sess.source_map();
cx,
&root_path,
highlight::DecorationInfo(decoration_info),
- sources::SourceContext::Embedded { offset: line_min },
+ sources::SourceContext::Embedded { offset: line_min, needs_expansion },
);
write!(w, "</div></div>");
use rustc_middle::middle::stability;
use rustc_middle::span_bug;
use rustc_middle::ty::layout::LayoutError;
-use rustc_middle::ty::{Adt, TyCtxt};
+use rustc_middle::ty::{self, Adt, TyCtxt};
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_target::abi::{Layout, Primitive, TagEncoding, Variants};
use crate::html::escape::Escape;
use crate::html::format::{
join_with_double_colon, print_abi_with_space, print_constness_with_space, print_where_clause,
- Buffer, Ending, PrintWithSpace,
+ visibility_print_with_space, Buffer, Ending, PrintWithSpace,
};
-use crate::html::highlight;
use crate::html::layout::Page;
use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine};
use crate::html::url_parts_builder::UrlPartsBuilder;
+use crate::html::{highlight, static_files};
use askama::Template;
use itertools::Itertools;
#[derive(Template)]
#[template(path = "print_item.html")]
struct ItemVars<'a> {
- page: &'a Page<'a>,
static_root_path: &'a str,
+ clipboard_svg: &'static static_files::StaticFile,
typ: &'a str,
name: &'a str,
item_type: &'a str,
};
let item_vars = ItemVars {
- page,
- static_root_path: page.get_static_root_path(),
+ static_root_path: &page.get_static_root_path(),
+ clipboard_svg: &static_files::STATIC_FILES.clipboard_svg,
typ,
name: item.name.as_ref().unwrap().as_str(),
item_type: &item.type_().to_string(),
);
}
+ let tcx = cx.tcx();
match *myitem.kind {
clean::ExternCrateItem { ref src } => {
use crate::html::format::anchor;
Some(src) => write!(
w,
"<div class=\"item-left\"><code>{}extern crate {} as {};",
- myitem.visibility.print_with_space(myitem.item_id, cx),
+ visibility_print_with_space(myitem.visibility(tcx), myitem.item_id, cx),
anchor(myitem.item_id.expect_def_id(), src, cx),
myitem.name.unwrap(),
),
None => write!(
w,
"<div class=\"item-left\"><code>{}extern crate {};",
- myitem.visibility.print_with_space(myitem.item_id, cx),
+ visibility_print_with_space(myitem.visibility(tcx), myitem.item_id, cx),
anchor(myitem.item_id.expect_def_id(), myitem.name.unwrap(), cx),
),
}
</div>\
{stab_tags_before}{stab_tags}{stab_tags_after}",
stab = stab.unwrap_or_default(),
- vis = myitem.visibility.print_with_space(myitem.item_id, cx),
+ vis = visibility_print_with_space(myitem.visibility(tcx), myitem.item_id, cx),
imp = import.print(cx),
);
w.write_str(ITEM_TABLE_ROW_CLOSE);
let stab = myitem.stability_class(cx.tcx());
let add = if stab.is_some() { " " } else { "" };
- let visibility_emoji = match myitem.visibility {
- clean::Visibility::Restricted(_) => {
+ let visibility_emoji = match myitem.visibility(tcx) {
+ Some(ty::Visibility::Restricted(_)) => {
"<span title=\"Restricted Visibility\"> 🔒</span> "
}
_ => "",
}
fn item_function(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, f: &clean::Function) {
- let header = it.fn_header(cx.tcx()).expect("printing a function which isn't a function");
- let constness = print_constness_with_space(&header.constness, it.const_stability(cx.tcx()));
+ let tcx = cx.tcx();
+ let header = it.fn_header(tcx).expect("printing a function which isn't a function");
+ let constness = print_constness_with_space(&header.constness, it.const_stability(tcx));
let unsafety = header.unsafety.print_with_space();
let abi = print_abi_with_space(header.abi).to_string();
let asyncness = header.asyncness.print_with_space();
- let visibility = it.visibility.print_with_space(it.item_id, cx).to_string();
+ let visibility = visibility_print_with_space(it.visibility(tcx), it.item_id, cx).to_string();
let name = it.name.unwrap();
let generics_len = format!("{:#}", f.generics.print(cx)).len();
}
fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Trait) {
+ let tcx = cx.tcx();
let bounds = bounds(&t.bounds, false, cx);
let required_types = t.items.iter().filter(|m| m.is_ty_associated_type()).collect::<Vec<_>>();
let provided_types = t.items.iter().filter(|m| m.is_associated_type()).collect::<Vec<_>>();
let count_types = required_types.len() + provided_types.len();
let count_consts = required_consts.len() + provided_consts.len();
let count_methods = required_methods.len() + provided_methods.len();
- let must_implement_one_of_functions =
- cx.tcx().trait_def(t.def_id).must_implement_one_of.clone();
+ let must_implement_one_of_functions = tcx.trait_def(t.def_id).must_implement_one_of.clone();
// Output the trait definition
wrap_into_item_decl(w, |w| {
write!(
w,
"{}{}{}trait {}{}{}",
- it.visibility.print_with_space(it.item_id, cx),
- t.unsafety(cx.tcx()).print_with_space(),
- if t.is_auto(cx.tcx()) { "auto " } else { "" },
+ visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
+ t.unsafety(tcx).print_with_space(),
+ if t.is_auto(tcx) { "auto " } else { "" },
it.name.unwrap(),
t.generics.print(cx),
bounds
}
let extern_crates = extern_crates
.into_iter()
- .map(|cnum| cx.shared.tcx.crate_name(cnum).to_string())
+ .map(|cnum| tcx.crate_name(cnum).to_string())
.collect::<Vec<_>>()
.join(",");
let (extern_before, extern_after) =
fn write_content(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Typedef) {
wrap_item(w, "typedef", |w| {
render_attributes_in_pre(w, it, "");
- write!(w, "{}", it.visibility.print_with_space(it.item_id, cx));
+ write!(w, "{}", visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx));
write!(
w,
"type {}{}{where_clause} = {type_};",
}
fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::Enum) {
+ let tcx = cx.tcx();
let count_variants = e.variants().count();
wrap_into_item_decl(w, |w| {
wrap_item(w, "enum", |w| {
write!(
w,
"{}enum {}{}",
- it.visibility.print_with_space(it.item_id, cx),
+ visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
it.name.unwrap(),
e.generics.print(cx),
);
w.write_str("</code>");
render_stability_since_raw(
w,
- variant.stable_since(cx.tcx()),
- variant.const_stability(cx.tcx()),
- it.stable_since(cx.tcx()),
- it.const_stable_since(cx.tcx()),
+ variant.stable_since(tcx),
+ variant.const_stability(tcx),
+ it.stable_since(tcx),
+ it.const_stable_since(tcx),
);
w.write_str("</h3>");
fn item_constant(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, c: &clean::Constant) {
wrap_into_item_decl(w, |w| {
wrap_item(w, "const", |w| {
+ let tcx = cx.tcx();
render_attributes_in_code(w, it);
write!(
w,
"{vis}const {name}: {typ}",
- vis = it.visibility.print_with_space(it.item_id, cx),
+ vis = visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
name = it.name.unwrap(),
typ = c.type_.print(cx),
);
// ` = 100i32;`
// instead?
- let value = c.value(cx.tcx());
- let is_literal = c.is_literal(cx.tcx());
- let expr = c.expr(cx.tcx());
+ let value = c.value(tcx);
+ let is_literal = c.is_literal(tcx);
+ let expr = c.expr(tcx);
if value.is_some() || is_literal {
write!(w, " = {expr};", expr = Escape(&expr));
} else {
write!(
w,
"{vis}static {mutability}{name}: {typ}",
- vis = it.visibility.print_with_space(it.item_id, cx),
+ vis = visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx),
mutability = s.mutability.print_with_space(),
name = it.name.unwrap(),
typ = s.type_.print(cx)
write!(
w,
" {}type {};\n}}",
- it.visibility.print_with_space(it.item_id, cx),
+ visibility_print_with_space(it.visibility(cx.tcx()), it.item_id, cx),
it.name.unwrap(),
);
});
tab: &str,
cx: &Context<'_>,
) {
- write!(w, "{}union {}", it.visibility.print_with_space(it.item_id, cx), it.name.unwrap(),);
+ let tcx = cx.tcx();
+ write!(
+ w,
+ "{}union {}",
+ visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
+ it.name.unwrap(),
+ );
let where_displayed = g
.map(|g| {
write!(
w,
" {}{}: {},\n{}",
- field.visibility.print_with_space(field.item_id, cx),
+ visibility_print_with_space(field.visibility(tcx), field.item_id, cx),
field.name.unwrap(),
ty.print(cx),
tab
structhead: bool,
cx: &Context<'_>,
) {
+ let tcx = cx.tcx();
write!(
w,
"{}{}{}",
- it.visibility.print_with_space(it.item_id, cx),
+ visibility_print_with_space(it.visibility(tcx), it.item_id, cx),
if structhead { "struct " } else { "" },
it.name.unwrap()
);
w,
"\n{} {}{}: {},",
tab,
- field.visibility.print_with_space(field.item_id, cx),
+ visibility_print_with_space(field.visibility(tcx), field.item_id, cx),
field.name.unwrap(),
ty.print(cx),
);
write!(
w,
"{}{}",
- field.visibility.print_with_space(field.item_id, cx),
+ visibility_print_with_space(field.visibility(tcx), field.item_id, cx),
ty.print(cx),
)
}
-use std::ffi::OsStr;
use std::fs::{self, File};
use std::io::prelude::*;
use std::io::{self, BufReader};
-use std::path::{Component, Path, PathBuf};
+use std::path::{Component, Path};
use std::rc::Rc;
-use std::sync::LazyLock as Lazy;
use itertools::Itertools;
use rustc_data_structures::flock;
use crate::html::{layout, static_files};
use crate::{try_err, try_none};
-static FILES_UNVERSIONED: Lazy<FxHashMap<&str, &[u8]>> = Lazy::new(|| {
- map! {
- "FiraSans-Regular.woff2" => static_files::fira_sans::REGULAR,
- "FiraSans-Medium.woff2" => static_files::fira_sans::MEDIUM,
- "FiraSans-LICENSE.txt" => static_files::fira_sans::LICENSE,
- "SourceSerif4-Regular.ttf.woff2" => static_files::source_serif_4::REGULAR,
- "SourceSerif4-Bold.ttf.woff2" => static_files::source_serif_4::BOLD,
- "SourceSerif4-It.ttf.woff2" => static_files::source_serif_4::ITALIC,
- "SourceSerif4-LICENSE.md" => static_files::source_serif_4::LICENSE,
- "SourceCodePro-Regular.ttf.woff2" => static_files::source_code_pro::REGULAR,
- "SourceCodePro-Semibold.ttf.woff2" => static_files::source_code_pro::SEMIBOLD,
- "SourceCodePro-It.ttf.woff2" => static_files::source_code_pro::ITALIC,
- "SourceCodePro-LICENSE.txt" => static_files::source_code_pro::LICENSE,
- "NanumBarunGothic.ttf.woff2" => static_files::nanum_barun_gothic::REGULAR,
- "NanumBarunGothic-LICENSE.txt" => static_files::nanum_barun_gothic::LICENSE,
- "LICENSE-MIT.txt" => static_files::LICENSE_MIT,
- "LICENSE-APACHE.txt" => static_files::LICENSE_APACHE,
- "COPYRIGHT.txt" => static_files::COPYRIGHT,
- }
-});
-
-enum SharedResource<'a> {
- /// This file will never change, no matter what toolchain is used to build it.
- ///
- /// It does not have a resource suffix.
- Unversioned { name: &'static str },
- /// This file may change depending on the toolchain.
- ///
- /// It has a resource suffix.
- ToolchainSpecific { basename: &'static str },
- /// This file may change for any crate within a build, or based on the CLI arguments.
- ///
- /// This differs from normal invocation-specific files because it has a resource suffix.
- InvocationSpecific { basename: &'a str },
-}
-
-impl SharedResource<'_> {
- fn extension(&self) -> Option<&OsStr> {
- use SharedResource::*;
- match self {
- Unversioned { name }
- | ToolchainSpecific { basename: name }
- | InvocationSpecific { basename: name } => Path::new(name).extension(),
- }
- }
-
- fn path(&self, cx: &Context<'_>) -> PathBuf {
- match self {
- SharedResource::Unversioned { name } => cx.dst.join(name),
- SharedResource::ToolchainSpecific { basename } => cx.suffix_path(basename),
- SharedResource::InvocationSpecific { basename } => cx.suffix_path(basename),
- }
- }
-
- fn should_emit(&self, emit: &[EmitType]) -> bool {
- if emit.is_empty() {
- return true;
- }
- let kind = match self {
- SharedResource::Unversioned { .. } => EmitType::Unversioned,
- SharedResource::ToolchainSpecific { .. } => EmitType::Toolchain,
- SharedResource::InvocationSpecific { .. } => EmitType::InvocationSpecific,
- };
- emit.contains(&kind)
- }
-}
-
-impl Context<'_> {
- fn suffix_path(&self, filename: &str) -> PathBuf {
- // We use splitn vs Path::extension here because we might get a filename
- // like `style.min.css` and we want to process that into
- // `style-suffix.min.css`. Path::extension would just return `css`
- // which would result in `style.min-suffix.css` which isn't what we
- // want.
- let (base, ext) = filename.split_once('.').unwrap();
- let filename = format!("{}{}.{}", base, self.shared.resource_suffix, ext);
- self.dst.join(&filename)
- }
-
- fn write_shared(
- &self,
- resource: SharedResource<'_>,
- contents: impl 'static + Send + AsRef<[u8]>,
- emit: &[EmitType],
- ) -> Result<(), Error> {
- if resource.should_emit(emit) {
- self.shared.fs.write(resource.path(self), contents)
- } else {
- Ok(())
- }
- }
-
- fn write_minify(
- &self,
- resource: SharedResource<'_>,
- contents: impl 'static + Send + AsRef<str> + AsRef<[u8]>,
- minify: bool,
- emit: &[EmitType],
- ) -> Result<(), Error> {
- if minify {
- let contents = contents.as_ref();
- let contents = if resource.extension() == Some(OsStr::new("css")) {
- minifier::css::minify(contents)
- .map_err(|e| {
- Error::new(format!("failed to minify CSS file: {}", e), resource.path(self))
- })?
- .to_string()
- } else {
- minifier::js::minify(contents).to_string()
- };
- self.write_shared(resource, contents, emit)
- } else {
- self.write_shared(resource, contents, emit)
- }
- }
-}
-
+/// Rustdoc writes out two kinds of shared files:
+/// - Static files, which are embedded in the rustdoc binary and are written with a
+/// filename that includes a hash of their contents. These will always have a new
+/// URL if the contents change, so they are safe to cache with the
+/// `Cache-Control: immutable` directive. They are written under the static.files/
+/// directory and are written when --emit-type is empty (default) or contains
+/// "toolchain-specific". If using the --static-root-path flag, it should point
+/// to a URL path prefix where each of these filenames can be fetched.
+/// - Invocation specific files. These are generated based on the crate(s) being
+/// documented. Their filenames need to be predictable without knowing their
+/// contents, so they do not include a hash in their filename and are not safe to
+/// cache with `Cache-Control: immutable`. They include the contents of the
+/// --resource-suffix flag and are emitted when --emit-type is empty (default)
+/// or contains "invocation-specific".
pub(super) fn write_shared(
cx: &mut Context<'_>,
krate: &Crate,
let lock_file = cx.dst.join(".lock");
let _lock = try_err!(flock::Lock::new(&lock_file, true, true, true), &lock_file);
- // Minified resources are usually toolchain resources. If they're not, they should use `cx.write_minify` directly.
- fn write_minify(
- basename: &'static str,
- contents: impl 'static + Send + AsRef<str> + AsRef<[u8]>,
- cx: &Context<'_>,
- options: &RenderOptions,
- ) -> Result<(), Error> {
- cx.write_minify(
- SharedResource::ToolchainSpecific { basename },
- contents,
- options.enable_minification,
- &options.emit,
- )
- }
-
- // Toolchain resources should never be dynamic.
- let write_toolchain = |p: &'static _, c: &'static _| {
- cx.write_shared(SharedResource::ToolchainSpecific { basename: p }, c, &options.emit)
- };
-
- // Crate resources should always be dynamic.
- let write_crate = |p: &_, make_content: &dyn Fn() -> Result<Vec<u8>, Error>| {
+ // InvocationSpecific resources should always be dynamic.
+ let write_invocation_specific = |p: &str, make_content: &dyn Fn() -> Result<Vec<u8>, Error>| {
let content = make_content()?;
- cx.write_shared(SharedResource::InvocationSpecific { basename: p }, content, &options.emit)
+ if options.emit.is_empty() || options.emit.contains(&EmitType::InvocationSpecific) {
+ let output_filename = static_files::suffix_path(p, &cx.shared.resource_suffix);
+ cx.shared.fs.write(cx.dst.join(output_filename), content)
+ } else {
+ Ok(())
+ }
};
- // Given "foo.svg", return e.g. "url(\"foo1.58.0.svg\")"
- fn ver_url(cx: &Context<'_>, basename: &'static str) -> String {
- format!(
- "url(\"{}\")",
- SharedResource::ToolchainSpecific { basename }
- .path(cx)
- .file_name()
- .unwrap()
- .to_str()
- .unwrap()
- )
- }
-
- // We use the AUTOREPLACE mechanism to inject into our static JS and CSS certain
- // values that are only known at doc build time. Since this mechanism is somewhat
- // surprising when reading the code, please limit it to rustdoc.css.
- write_minify(
- "rustdoc.css",
- static_files::RUSTDOC_CSS
- .replace(
- "/* AUTOREPLACE: */url(\"toggle-minus.svg\")",
- &ver_url(cx, "toggle-minus.svg"),
- )
- .replace("/* AUTOREPLACE: */url(\"toggle-plus.svg\")", &ver_url(cx, "toggle-plus.svg"))
- .replace("/* AUTOREPLACE: */url(\"down-arrow.svg\")", &ver_url(cx, "down-arrow.svg")),
- cx,
- options,
- )?;
-
- // Add all the static files. These may already exist, but we just
- // overwrite them anyway to make sure that they're fresh and up-to-date.
- write_minify("settings.css", static_files::SETTINGS_CSS, cx, options)?;
- write_minify("noscript.css", static_files::NOSCRIPT_CSS, cx, options)?;
-
- // To avoid "light.css" to be overwritten, we'll first run over the received themes and only
- // then we'll run over the "official" styles.
- let mut themes: FxHashSet<String> = FxHashSet::default();
+ cx.shared
+ .fs
+ .create_dir_all(cx.dst.join("static.files"))
+ .map_err(|e| PathError::new(e, "static.files"))?;
+ // Handle added third-party themes
for entry in &cx.shared.style_files {
let theme = entry.basename()?;
let extension =
try_none!(try_none!(entry.path.extension(), &entry.path).to_str(), &entry.path);
- // Handle the official themes
- match theme.as_str() {
- "light" => write_minify("light.css", static_files::themes::LIGHT, cx, options)?,
- "dark" => write_minify("dark.css", static_files::themes::DARK, cx, options)?,
- "ayu" => write_minify("ayu.css", static_files::themes::AYU, cx, options)?,
- _ => {
- // Handle added third-party themes
- let filename = format!("{}.{}", theme, extension);
- write_crate(&filename, &|| Ok(try_err!(fs::read(&entry.path), &entry.path)))?;
- }
- };
-
- themes.insert(theme.to_owned());
- }
-
- if (*cx.shared).layout.logo.is_empty() {
- write_toolchain("rust-logo.svg", static_files::RUST_LOGO_SVG)?;
- }
- if (*cx.shared).layout.favicon.is_empty() {
- write_toolchain("favicon.svg", static_files::RUST_FAVICON_SVG)?;
- write_toolchain("favicon-16x16.png", static_files::RUST_FAVICON_PNG_16)?;
- write_toolchain("favicon-32x32.png", static_files::RUST_FAVICON_PNG_32)?;
- }
- write_toolchain("wheel.svg", static_files::WHEEL_SVG)?;
- write_toolchain("clipboard.svg", static_files::CLIPBOARD_SVG)?;
- write_toolchain("down-arrow.svg", static_files::DOWN_ARROW_SVG)?;
- write_toolchain("toggle-minus.svg", static_files::TOGGLE_MINUS_PNG)?;
- write_toolchain("toggle-plus.svg", static_files::TOGGLE_PLUS_PNG)?;
-
- let mut themes: Vec<&String> = themes.iter().collect();
- themes.sort();
-
- write_minify("main.js", static_files::MAIN_JS, cx, options)?;
- write_minify("search.js", static_files::SEARCH_JS, cx, options)?;
- write_minify("settings.js", static_files::SETTINGS_JS, cx, options)?;
-
- if cx.include_sources {
- write_minify("source-script.js", static_files::sidebar::SOURCE_SCRIPT, cx, options)?;
- }
-
- write_minify("storage.js", static_files::STORAGE_JS, cx, options)?;
+ // Skip the official themes. They are written below as part of STATIC_FILES_LIST.
+ if matches!(theme.as_str(), "light" | "dark" | "ayu") {
+ continue;
+ }
- if cx.shared.layout.scrape_examples_extension {
- cx.write_minify(
- SharedResource::InvocationSpecific { basename: "scrape-examples.js" },
- static_files::SCRAPE_EXAMPLES_JS,
- options.enable_minification,
- &options.emit,
- )?;
+ let bytes = try_err!(fs::read(&entry.path), &entry.path);
+ let filename = format!("{}{}.{}", theme, cx.shared.resource_suffix, extension);
+ cx.shared.fs.write(cx.dst.join(filename), bytes)?;
}
+ // When the user adds their own CSS files with --extend-css, we write that as an
+ // invocation-specific file (that is, with a resource suffix).
if let Some(ref css) = cx.shared.layout.css_file_extension {
let buffer = try_err!(fs::read_to_string(css), css);
- // This varies based on the invocation, so it can't go through the write_minify wrapper.
- cx.write_minify(
- SharedResource::InvocationSpecific { basename: "theme.css" },
- buffer,
- options.enable_minification,
- &options.emit,
- )?;
+ let path = static_files::suffix_path("theme.css", &cx.shared.resource_suffix);
+ cx.shared.fs.write(cx.dst.join(path), buffer)?;
}
- write_minify("normalize.css", static_files::NORMALIZE_CSS, cx, options)?;
- for (name, contents) in &*FILES_UNVERSIONED {
- cx.write_shared(SharedResource::Unversioned { name }, contents, &options.emit)?;
+
+ if options.emit.is_empty() || options.emit.contains(&EmitType::Toolchain) {
+ let static_dir = cx.dst.join(Path::new("static.files"));
+ static_files::for_each(|f: &static_files::StaticFile| {
+ let filename = static_dir.join(f.output_filename());
+ cx.shared.fs.write(filename, f.minified())
+ })?;
}
/// Read a file and return all lines that match the `"{crate}":{data},` format,
v.push_str("\\\n}');\ncreateSourceSidebar();\n");
Ok(v.into_bytes())
};
- write_crate("source-files.js", &make_sources)?;
+ write_invocation_specific("source-files.js", &make_sources)?;
}
// Update the search index and crate list.
// Sort the indexes by crate so the file will be generated identically even
// with rustdoc running in parallel.
all_indexes.sort();
- write_crate("search-index.js", &|| {
+ write_invocation_specific("search-index.js", &|| {
let mut v = String::from("var searchIndex = JSON.parse('{\\\n");
v.push_str(&all_indexes.join(",\\\n"));
v.push_str(
Ok(v.into_bytes())
})?;
- write_crate("crates.js", &|| {
+ write_invocation_specific("crates.js", &|| {
let krates = krates.iter().map(|k| format!("\"{}\"", k)).join(",");
Ok(format!("window.ALL_CRATES = [{}];", krates).into_bytes())
})?;
pub(crate) enum SourceContext {
Standalone,
- Embedded { offset: usize },
+ Embedded { offset: usize, needs_expansion: bool },
}
/// Wrapper struct to render the source code of a file. This will do things like
) {
let lines = s.lines().count();
let mut line_numbers = Buffer::empty_from(buf);
+ let extra;
line_numbers.write_str("<pre class=\"src-line-numbers\">");
match source_context {
SourceContext::Standalone => {
+ extra = None;
for line in 1..=lines {
writeln!(line_numbers, "<span id=\"{0}\">{0}</span>", line)
}
}
- SourceContext::Embedded { offset } => {
+ SourceContext::Embedded { offset, needs_expansion } => {
+ extra =
+ if needs_expansion { Some(r#"<span class="expand">↕</span>"#) } else { None };
for line in 1..=lines {
writeln!(line_numbers, "<span>{0}</span>", line + offset)
}
line_numbers,
highlight::HrefContext { context, file_span, root_path, current_href },
decoration_info,
+ extra,
);
}
font-style: normal;
font-weight: 400;
src: local('Fira Sans'),
- url("FiraSans-Regular.woff2") format("woff2");
+ url("FiraSans-Regular-018c141bf0843ffd.woff2") format("woff2");
font-display: swap;
}
@font-face {
font-style: normal;
font-weight: 500;
src: local('Fira Sans Medium'),
- url("FiraSans-Medium.woff2") format("woff2");
+ url("FiraSans-Medium-8f9a781e4970d388.woff2") format("woff2");
font-display: swap;
}
font-style: normal;
font-weight: 400;
src: local('Source Serif 4'),
- url("SourceSerif4-Regular.ttf.woff2") format("woff2");
+ url("SourceSerif4-Regular-1f7d512b176f0f72.ttf.woff2") format("woff2");
font-display: swap;
}
@font-face {
font-style: italic;
font-weight: 400;
src: local('Source Serif 4 Italic'),
- url("SourceSerif4-It.ttf.woff2") format("woff2");
+ url("SourceSerif4-It-d034fe4ef9d0fa00.ttf.woff2") format("woff2");
font-display: swap;
}
@font-face {
font-style: normal;
font-weight: 700;
src: local('Source Serif 4 Bold'),
- url("SourceSerif4-Bold.ttf.woff2") format("woff2");
+ url("SourceSerif4-Bold-124a1ca42af929b6.ttf.woff2") format("woff2");
font-display: swap;
}
font-weight: 400;
/* Avoid using locally installed font because bad versions are in circulation:
* see https://github.com/rust-lang/rust/issues/24355 */
- src: url("SourceCodePro-Regular.ttf.woff2") format("woff2");
+ src: url("SourceCodePro-Regular-562dcc5011b6de7d.ttf.woff2") format("woff2");
font-display: swap;
}
@font-face {
font-family: 'Source Code Pro';
font-style: italic;
font-weight: 400;
- src: url("SourceCodePro-It.ttf.woff2") format("woff2");
+ src: url("SourceCodePro-It-1cc31594bf4f1f79.ttf.woff2") format("woff2");
font-display: swap;
}
@font-face {
font-family: 'Source Code Pro';
font-style: normal;
font-weight: 600;
- src: url("SourceCodePro-Semibold.ttf.woff2") format("woff2");
+ src: url("SourceCodePro-Semibold-d899c5a5c4aeb14a.ttf.woff2") format("woff2");
font-display: swap;
}
/* Avoid using legacy CJK serif fonts in Windows like Batang. */
@font-face {
font-family: 'NanumBarunGothic';
- src: url("NanumBarunGothic.ttf.woff2") format("woff2");
+ src: url("NanumBarunGothic-0f09457c7a19b7c6.ttf.woff2") format("woff2");
font-display: swap;
unicode-range: U+AC00-D7AF, U+1100-11FF, U+3130-318F, U+A960-A97F, U+D7B0-D7FF;
}
padding-bottom: 6px;
margin-bottom: 15px;
}
-#toggle-all-docs {
- text-decoration: none;
-}
/* The only headings that get underlines are:
Markdown-generated headings within the top-doc
Rustdoc-generated h2 section headings (e.g. "Implementations", "Required Methods", etc)
font-family: "Fira Sans", Arial, NanumBarunGothic, sans-serif;
}
-a#toggle-all-docs,
+#toggle-all-docs,
a.anchor,
.small-section-header a,
#source-sidebar a,
margin: 0;
}
-summary {
- outline: none;
-}
-
/* Fix some style changes due to normalize.css 8 */
button {
padding: 1px 6px;
}
+button#toggle-all-docs {
+ padding: 0;
+ background: none;
+ border: none;
+ cursor: pointer;
+ /* iOS button gradient: https://stackoverflow.com/q/5438567 */
+ -webkit-appearance: none;
+ opacity: 1;
+}
+
/* end tweaks for normalize.css 8 */
.rustdoc {
overflow: visible;
}
-.sub-logo-container {
+.sub-logo-container, .logo-container {
+ /* zero text boxes so that computed line height = image height exactly */
line-height: 0;
}
object-fit: contain;
}
+.rust-logo {
+ filter: var(--rust-logo-filter);
+}
+
.sidebar, .mobile-topbar, .sidebar-menu-toggle {
background-color: var(--sidebar-background-color);
}
}
.sidebar .logo-container {
- display: flex;
margin-top: 10px;
margin-bottom: 10px;
- justify-content: center;
+ text-align: center;
}
.version {
.sidebar h2 {
overflow-wrap: anywhere;
padding: 0;
- margin: 0;
- margin-top: 0.7rem;
- margin-bottom: 0.7rem;
+ margin: 0.7rem 0;
}
.sidebar h3 {
padding: 13px 8px;
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
+ border-color: var(--example-line-numbers-border-color);
}
.src-line-numbers span {
cursor: pointer;
+ color: var(--src-line-numbers-span-color);
+}
+.src-line-numbers .line-highlighted {
+ background-color: var(--src-line-number-highlighted-background-color);
+}
+.src-line-numbers :target {
+ background-color: transparent;
}
.search-loading {
}
#main-content > .item-info {
- margin-top: 0;
margin-left: 0;
}
display: flex;
align-items: center;
}
-nav.sub form {
+.search-form {
+ position: relative;
+ display: flex;
+ height: 34px;
flex-grow: 1;
}
.source nav.sub {
margin: 0 0 15px 0;
}
-.source nav.sub form {
+.source .search-form {
margin-left: 32px;
}
padding-right: 1.25rem;
}
-.search-container {
- position: relative;
- display: flex;
- height: 34px;
-}
.search-results-title {
margin-top: 0;
white-space: nowrap;
}
#crate-search {
min-width: 115px;
- padding: 0;
/* keep these two in sync with "@-moz-document url-prefix()" below */
- padding-left: 4px;
- padding-right: 23px;
+ padding: 0 23px 0 4px;
/* prevents the <select> from overflowing the containing div in case it's shrunk */
max-width: 100%;
/* contents can overflow because of max-width limit, then show ellipsis */
background-size: 20px;
background-position: calc(100% - 2px) 56%;
/* image is black color, themes should apply a "filter" property to change the color */
- background-image: /* AUTOREPLACE: */url("down-arrow.svg");
+ background-image: url("down-arrow-927217e04c7463ac.svg");
}
#crate-search > option {
font-size: 1rem;
-webkit-appearance: textfield for search inputs. That
causes rounded corners and no border on iOS Safari. */
-webkit-appearance: none;
- /* Override Normalize.css: we have margins and do
- not want to overflow - the `moz` attribute is necessary
- until Firefox 29, too early to drop at this point */
- -moz-box-sizing: border-box !important;
- box-sizing: border-box !important;
outline: none;
border: 1px solid var(--border-color);
border-radius: 2px;
padding: 8px;
font-size: 1rem;
- width: 100%;
+ flex-grow: 1;
background-color: var(--button-background-color);
color: var(--search-color);
}
.search-results {
display: none;
- padding-bottom: 2em;
}
.search-results.active {
display: block;
- /* prevent overhanging tabs from moving the first result */
- clear: both;
-}
-
-.search-results .desc > span {
- white-space: nowrap;
- text-overflow: ellipsis;
- overflow: hidden;
- display: block;
}
.search-results > a {
- display: block;
+ display: flex;
/* A little margin ensures the browser's outlining of focused links has room to display. */
margin-left: 2px;
margin-right: 2px;
- border-bottom: 1px solid #aaa3;
+ border-bottom: 1px solid var(--search-result-border-color);
+ gap: 1em;
}
.search-results > a > div {
- display: flex;
- flex-flow: row wrap;
+ flex: 1;
}
-.search-results .result-name, .search-results div.desc {
- width: 50%;
-}
-.search-results .result-name {
- padding-right: 1em;
+.search-results > a > div.desc {
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ display: block;
}
.search-results a:hover,
pre.rust .self {
color: var(--code-highlight-self-color);
}
-pre.rust .attribute {
+pre.rust .attr {
color: var(--code-highlight-attribute-color);
}
pre.rust .macro,
top: 5px;
right: 5px;
z-index: 1;
+ color: var(--test-arrow-color);
+ background-color: var(--test-arrow-background-color);
+}
+a.test-arrow:hover {
+ color: var(--test-arrow-hover-color);
+ background-color: var(--test-arrow-hover-background-color);
}
.example-wrap:hover .test-arrow {
visibility: visible;
content: "\00a0\00a0\00a0";
}
-.notable-traits .notable, .notable-traits .docblock {
+.notable-traits .docblock {
margin: 0;
}
details.rustdoc-toggle > summary {
list-style: none;
+ /* focus outline is shown on `::before` instead of this */
+ outline: none;
}
details.rustdoc-toggle > summary::-webkit-details-marker,
details.rustdoc-toggle > summary::marker {
details.rustdoc-toggle[open] > summary::before,
details.rustdoc-toggle[open] > summary.hideme::before {
- background-image: /* AUTOREPLACE: */url("toggle-minus.svg");
+ background-image: url("toggle-minus-31bbd6e4c77f5c96.svg");
}
details.rustdoc-toggle > summary::before {
- background-image: /* AUTOREPLACE: */url("toggle-plus.svg");
+ background-image: url("toggle-plus-1092eb4930d581b0.svg");
}
details.rustdoc-toggle[open] > summary::before,
}
.rustdoc {
- padding-top: 0px;
/* Sidebar should overlay main content, rather than pushing main content to the right.
Turn off `display: flex` on the body element. */
display: block;
/* Hide the sidebar offscreen while not in use. Doing this instead of display: none means
the sidebar stays visible for screen readers, which is useful for navigation. */
left: -1000px;
- margin-left: 0;
margin: 0;
padding: 0;
z-index: 11;
white-space: nowrap;
}
- .mobile-topbar .logo-container {
- max-height: 45px;
- }
-
.mobile-topbar .logo-container > img {
max-width: 35px;
max-height: 35px;
- margin-left: 20px;
- margin-top: 5px;
- margin-bottom: 5px;
+ margin: 5px 0 5px 20px;
}
.mobile-topbar {
.sidebar-elems {
margin-top: 1em;
- background-color: var(--sidebar-background-color);
}
.content {
display: block;
}
- /* Because of ios, we need to actually have a full height sidebar title so the
- * actual sidebar can show up. But then we need to make it transparent so we don't
- * hide content. The filler just allows to create the background for the sidebar
- * title. But because of the absolute position, I had to lower the z-index.
- */
- #sidebar-filler {
- position: fixed;
- left: 45px;
- width: calc(100% - 45px);
- top: 0;
- height: 45px;
- z-index: -1;
- border-bottom: 1px solid;
- }
-
#main-content > details.rustdoc-toggle > summary::before,
#main-content > div > details.rustdoc-toggle > summary::before {
left: -11px;
}
/* Display an alternating layout on tablets and phones */
- .item-table {
+ .item-table, .item-row, .item-left, .item-right,
+ .search-results > a, .search-results > a > div {
display: block;
}
- .item-row {
- display: flex;
- flex-flow: column wrap;
- }
- .item-left, .item-right {
- width: 100%;
- }
/* Display an alternating layout on tablets and phones */
.search-results > a {
- border-bottom: 1px solid #aaa9;
padding: 5px 0px;
}
- .search-results .result-name, .search-results div.desc {
- width: 100%;
- }
- .search-results div.desc, .item-right {
+ .search-results > a > div.desc, .item-right {
padding-left: 2em;
}
flex-direction: column;
}
- nav.sub form {
+ .search-form {
align-self: stretch;
}
}
}
-.method-toggle > summary,
.implementors-toggle > summary,
.impl,
#implementors-list > .docblock,
.impl-items > section,
-.methods > section
+.impl-items > .rustdoc-toggle > summary,
+.methods > section,
+.methods > .rustdoc-toggle > summary
{
margin-bottom: 0.75em;
}
-.method-toggle[open]:not(:last-child),
+.impl-items > .rustdoc-toggle[open]:not(:last-child),
+.methods > .rustdoc-toggle[open]:not(:last-child),
.implementors-toggle[open]:not(:last-child) {
margin-bottom: 2em;
}
-#trait-implementations-list .method-toggle:not(:last-child),
-#synthetic-implementations-list .method-toggle:not(:last-child),
-#blanket-implementations-list .method-toggle:not(:last-child) {
+#trait-implementations-list .impl-items > .rustdoc-toggle:not(:last-child),
+#synthetic-implementations-list .impl-items > .rustdoc-toggle:not(:last-child),
+#blanket-implementations-list .impl-items > .rustdoc-toggle:not(:last-child) {
margin-bottom: 1em;
}
padding-bottom: 0;
}
-.scraped-example .code-wrapper .prev {
+.scraped-example .code-wrapper .next,
+.scraped-example .code-wrapper .prev,
+.scraped-example .code-wrapper .expand {
position: absolute;
top: 0.25em;
- right: 2.25em;
- z-index: 100;
+ z-index: 1;
cursor: pointer;
}
-
+.scraped-example .code-wrapper .prev {
+ right: 2.25em;
+}
.scraped-example .code-wrapper .next {
- position: absolute;
- top: 0.25em;
right: 1.25em;
- z-index: 100;
- cursor: pointer;
}
-
.scraped-example .code-wrapper .expand {
- position: absolute;
- top: 0.25em;
right: 0.25em;
- z-index: 100;
- cursor: pointer;
}
-.scraped-example:not(.expanded) .code-wrapper:before {
+.scraped-example:not(.expanded) .code-wrapper:before,
+.scraped-example:not(.expanded) .code-wrapper:after {
content: " ";
width: 100%;
height: 5px;
position: absolute;
- z-index: 100;
+ z-index: 1;
+}
+.scraped-example:not(.expanded) .code-wrapper:before {
top: 0;
}
-
.scraped-example:not(.expanded) .code-wrapper:after {
- content: " ";
- width: 100%;
- height: 5px;
- position: absolute;
- z-index: 100;
bottom: 0;
}
--sidebar-link-color: #53b1db;
--sidebar-current-link-background-color: transparent;
--search-result-link-focus-background-color: #3c3c3c;
+ --search-result-border-color: #aaa3;
--stab-background-color: #314559;
--stab-code-color: #e6e1cf;
--search-color: #fff;
--code-highlight-question-mark-color: #ff9011;
--code-highlight-comment-color: #788797;
--code-highlight-doc-comment-color: #a1ac88;
+ --example-line-numbers-border-color: none;
+ --src-line-numbers-span-color: #5c6773;
+ --src-line-number-highlighted-background-color: rgba(255, 236, 164, 0.06);
+ --test-arrow-color: #788797;
+ --test-arrow-background-color: rgba(57, 175, 215, 0.09);
+ --test-arrow-hover-color: #c5c5c5;
+ --test-arrow-hover-background-color: rgba(57, 175, 215, 0.368);
+ --rust-logo-filter: drop-shadow(1px 0 0px #fff)
+ drop-shadow(0 1px 0 #fff)
+ drop-shadow(-1px 0 0 #fff)
+ drop-shadow(0 -1px 0 #fff);
}
.slider {
color: #e6e1cf;
}
-.rust-logo {
- filter: drop-shadow(1px 0 0px #fff)
- drop-shadow(0 1px 0 #fff)
- drop-shadow(-1px 0 0 #fff)
- drop-shadow(0 -1px 0 #fff);
-}
-
.sidebar .current,
.sidebar a:hover {
color: #ffb44c;
color: #ff7733;
}
-.src-line-numbers span { color: #5c6773; }
.src-line-numbers .line-highlighted {
color: #708090;
- background-color: rgba(255, 236, 164, 0.06);
padding-right: 4px;
border-right: 1px solid #ffb44c;
}
color: #788797;
}
-.src-line-numbers :target { background-color: transparent; }
-
-pre.example-line-numbers {
- color: #5c67736e;
- border: none;
-}
-
-a.test-arrow {
- font-size: 100%;
- color: #788797;
- border-radius: 4px;
- background-color: rgba(57, 175, 215, 0.09);
-}
-
-a.test-arrow:hover {
- background-color: rgba(57, 175, 215, 0.368);
- color: #c5c5c5;
-}
-
:target {
background: rgba(255, 236, 164, 0.06);
border-right: 3px solid rgba(255, 180, 76, 0.85);
--sidebar-link-color: #fdbf35;
--sidebar-current-link-background-color: #444;
--search-result-link-focus-background-color: #616161;
+ --search-result-border-color: #aaa3;
--stab-background-color: #314559;
--stab-code-color: #e6e1cf;
--search-color: #111;
--code-highlight-question-mark-color: #ff9011;
--code-highlight-comment-color: #8d8d8b;
--code-highlight-doc-comment-color: #8ca375;
+ --example-line-numbers-border-color: #4a4949;
+ --src-line-numbers-span-color: #3b91e2;
+ --src-line-number-highlighted-background-color: #0a042f;
+ --test-arrow-color: #dedede;
+ --test-arrow-background-color: rgba(78, 139, 202, 0.2);
+ --test-arrow-hover-color: #dedede;
+ --test-arrow-hover-background-color: #4e8bca;
+ --rust-logo-filter: drop-shadow(1px 0 0px #fff)
+ drop-shadow(0 1px 0 #fff)
+ drop-shadow(-1px 0 0 #fff)
+ drop-shadow(0 -1px 0 #fff);
}
.slider {
box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3);
}
-.rust-logo {
- filter: drop-shadow(1px 0 0px #fff)
- drop-shadow(0 1px 0 #fff)
- drop-shadow(-1px 0 0 #fff)
- drop-shadow(0 -1px 0 #fff)
-}
-
-.src-line-numbers span { color: #3B91E2; }
-.src-line-numbers .line-highlighted {
- background-color: #0a042f !important;
-}
-
.content .item-info::before { color: #ccc; }
body.source .example-wrap pre.rust a {
filter: invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg) brightness(100%) contrast(91%);
}
-.src-line-numbers :target { background-color: transparent; }
-
-pre.example-line-numbers {
- border-color: #4a4949;
-}
-
-a.test-arrow {
- color: #dedede;
- background-color: rgba(78, 139, 202, 0.2);
-}
-
-a.test-arrow:hover{
- background-color: #4e8bca;
-}
-
:target {
background-color: #494a3d;
border-right: 3px solid #bb7410;
--sidebar-link-color: #356da4;
--sidebar-current-link-background-color: #fff;
--search-result-link-focus-background-color: #ccc;
+ --search-result-border-color: #aaa3;
--stab-background-color: #fff5d6;
--stab-code-color: #000;
--search-color: #000;
--code-highlight-question-mark-color: #ff9011;
--code-highlight-comment-color: #8e908c;
--code-highlight-doc-comment-color: #4d4d4c;
+ --example-line-numbers-border-color: #c7c7c7;
+ --src-line-numbers-span-color: #c67e2d;
+ --src-line-number-highlighted-background-color: #fdffd3;
+ --test-arrow-color: #f5f5f5;
+ --test-arrow-background-color: rgba(78, 139, 202, 0.2);
+ --test-arrow-hover-color: #f5f5f5;
+ --test-arrow-hover-background-color: #4e8bca;
+ --rust-logo-filter: initial;
}
.slider {
box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3);
}
-.rust-logo {
- /* This rule exists to force other themes to explicitly style the logo.
- * Rustdoc has a custom linter for this purpose.
- */
-}
-
-.src-line-numbers span { color: #c67e2d; }
-.src-line-numbers .line-highlighted {
- background-color: #FDFFD3 !important;
-}
-
.content .item-info::before { color: #ccc; }
body.source .example-wrap pre.rust a {
filter: invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg) brightness(96%) contrast(93%);
}
-.src-line-numbers :target { background-color: transparent; }
-
-pre.example-line-numbers {
- border-color: #c7c7c7;
-}
-
-a.test-arrow {
- color: #f5f5f5;
- background-color: rgba(78, 139, 202, 0.2);
-}
-
-a.test-arrow:hover{
- background-color: #4e8bca;
-}
-
:target {
background: #FDFFD3;
border-right: 3px solid #AD7C37;
--- /dev/null
+The Nanum Barun Gothic fonts are shipped with rustdoc because the default fonts
+on many Windows installs render Korean very badly. See:
+ - https://github.com/rust-lang/rust/pull/84048,
+ - https://github.com/rust-lang/rust/issues/84035
+ - https://github.com/rust-lang/rust/pull/90232
+
+The font files were generated with these commands:
+
+```sh
+pyftsubset NanumBarunGothic.ttf \
+--unicodes=U+AC00-D7AF:U+1100-11FF,U+3130-318F,U+A960-A97F,U+D7B0-D7FF \
+--output-file=NanumBarunGothic.ttf.woff2 --flavor=woff2
}
// eslint-disable-next-line no-unused-vars
-function loadCss(cssFileName) {
+function loadCss(cssUrl) {
const link = document.createElement("link");
- link.href = resourcePath(cssFileName, ".css");
+ link.href = cssUrl;
link.type = "text/css";
link.rel = "stylesheet";
document.getElementsByTagName("head")[0].appendChild(link);
event.preventDefault();
// Sending request for the CSS and the JS files at the same time so it will
// hopefully be loaded when the JS will generate the settings content.
- loadCss("settings");
- loadScript(resourcePath("settings", ".js"));
+ loadCss(getVar("static-root-path") + getVar("settings-css"));
+ loadScript(getVar("static-root-path") + getVar("settings-js"));
};
window.searchState = {
function loadSearch() {
if (!searchLoaded) {
searchLoaded = true;
- loadScript(resourcePath("search", ".js"));
+ loadScript(getVar("static-root-path") + getVar("search-js"));
loadScript(resourcePath("search-index", ".js"));
}
}
* Hide all the popover menus.
*/
window.hidePopoverMenus = function() {
- onEachLazy(document.querySelectorAll(".search-container .popover"), elem => {
+ onEachLazy(document.querySelectorAll(".search-form .popover"), elem => {
elem.style.display = "none";
});
};
link.className = "result-" + type;
link.href = item.href;
- const wrapper = document.createElement("div");
const resultName = document.createElement("div");
resultName.className = "result-name";
resultName.insertAdjacentHTML(
"beforeend",
item.displayPath + "<span class=\"" + type + "\">" + name + extra + "</span>");
- wrapper.appendChild(resultName);
+ link.appendChild(resultName);
const description = document.createElement("div");
description.className = "desc";
- const spanDesc = document.createElement("span");
- spanDesc.insertAdjacentHTML("beforeend", item.desc);
+ description.insertAdjacentHTML("beforeend", item.desc);
- description.appendChild(spanDesc);
- wrapper.appendChild(description);
- link.appendChild(wrapper);
+ link.appendChild(description);
output.appendChild(link);
});
} else if (query.error === null) {
* @return {HTMLElement}
*/
function buildSettingsPage() {
- const themes = getVar("themes").split(",");
+ const theme_names = getVar("themes").split(",").filter(t => t);
+ theme_names.push("light", "dark", "ayu");
+
const settings = [
{
"name": "Use system theme",
"name": "Theme",
"js_name": "theme",
"default": "light",
- "options": themes,
+ "options": theme_names,
},
{
"name": "Preferred light theme",
"js_name": "preferred-light-theme",
"default": "light",
- "options": themes,
+ "options": theme_names,
},
{
"name": "Preferred dark theme",
"js_name": "preferred-dark-theme",
"default": "dark",
- "options": themes,
+ "options": theme_names,
},
{
"name": "Auto-hide item contents for large items",
}
}
-function switchTheme(styleElem, mainStyleElem, newTheme, saveTheme) {
- const newHref = mainStyleElem.href.replace(
- /\/rustdoc([^/]*)\.css/, "/" + newTheme + "$1" + ".css");
-
+function switchTheme(styleElem, mainStyleElem, newThemeName, saveTheme) {
// If this new value comes from a system setting or from the previously
// saved theme, no need to save it.
if (saveTheme) {
- updateLocalStorage("theme", newTheme);
- }
-
- if (styleElem.href === newHref) {
- return;
+ updateLocalStorage("theme", newThemeName);
}
- let found = false;
if (savedHref.length === 0) {
onEachLazy(document.getElementsByTagName("link"), el => {
savedHref.push(el.href);
});
}
- onEach(savedHref, el => {
- if (el === newHref) {
- found = true;
+ const newHref = savedHref.find(url => {
+ const m = url.match(/static\.files\/(.*)-[a-f0-9]{16}\.css$/);
+ if (m && m[1] === newThemeName) {
+ return true;
+ }
+ const m2 = url.match(/\/([^/]*)\.css$/);
+ if (m2 && m2[1].startsWith(newThemeName)) {
return true;
}
});
- if (found) {
+ if (newHref && newHref !== styleElem.href) {
styleElem.href = newHref;
}
}
//!
//! All the static files are included here for centralized access in case anything other than the
//! HTML rendering code (say, the theme checker) needs to access one of these files.
-//!
-//! Note about types: CSS and JavaScript files are included as `&'static str` to allow for the
-//! minifier to run on them. All other files are included as `&'static [u8]` so they can be
-//! directly written to a `Write` handle.
-
-/// The file contents of the main `rustdoc.css` file, responsible for the core layout of the page.
-pub(crate) static RUSTDOC_CSS: &str = include_str!("static/css/rustdoc.css");
-
-/// The file contents of `settings.css`, responsible for the items on the settings page.
-pub(crate) static SETTINGS_CSS: &str = include_str!("static/css/settings.css");
-
-/// The file contents of the `noscript.css` file, used in case JS isn't supported or is disabled.
-pub(crate) static NOSCRIPT_CSS: &str = include_str!("static/css/noscript.css");
-
-/// The file contents of `normalize.css`, included to even out standard elements between browser
-/// implementations.
-pub(crate) static NORMALIZE_CSS: &str = include_str!("static/css/normalize.css");
-
-/// The file contents of `main.js`, which contains the core JavaScript used on documentation pages,
-/// including search behavior and docblock folding, among others.
-pub(crate) static MAIN_JS: &str = include_str!("static/js/main.js");
-
-/// The file contents of `search.js`, which contains the search behavior.
-pub(crate) static SEARCH_JS: &str = include_str!("static/js/search.js");
-
-/// The file contents of `settings.js`, which contains the JavaScript used to handle the settings
-/// page.
-pub(crate) static SETTINGS_JS: &str = include_str!("static/js/settings.js");
-
-/// The file contents of `storage.js`, which contains functionality related to browser Local
-/// Storage, used to store documentation settings.
-pub(crate) static STORAGE_JS: &str = include_str!("static/js/storage.js");
-
-/// The file contents of `scraped-examples.js`, which contains functionality related to the
-/// --scrape-examples flag that inserts automatically-found examples of usages of items.
-pub(crate) static SCRAPE_EXAMPLES_JS: &str = include_str!("static/js/scrape-examples.js");
-
-pub(crate) static SCRAPE_EXAMPLES_HELP_MD: &str = include_str!("static/scrape-examples-help.md");
-
-/// The file contents of `wheel.svg`, the icon used for the settings button.
-pub(crate) static WHEEL_SVG: &[u8] = include_bytes!("static/images/wheel.svg");
-
-/// The file contents of `clipboard.svg`, the icon used for the "copy path" button.
-pub(crate) static CLIPBOARD_SVG: &[u8] = include_bytes!("static/images/clipboard.svg");
-
-/// The file contents of `down-arrow.svg`, the icon used for the crate choice combobox.
-pub(crate) static DOWN_ARROW_SVG: &[u8] = include_bytes!("static/images/down-arrow.svg");
-
-/// The file contents of `toggle-minus.svg`, the icon used for opened toggles.
-pub(crate) static TOGGLE_MINUS_PNG: &[u8] = include_bytes!("static/images/toggle-minus.svg");
-
-/// The file contents of `toggle-plus.svg`, the icon used for closed toggles.
-pub(crate) static TOGGLE_PLUS_PNG: &[u8] = include_bytes!("static/images/toggle-plus.svg");
-/// The contents of `COPYRIGHT.txt`, the license listing for files distributed with documentation
-/// output.
-pub(crate) static COPYRIGHT: &[u8] = include_bytes!("static/COPYRIGHT.txt");
+use rustc_data_structures::fx::FxHasher;
+use std::hash::Hasher;
+use std::path::{Path, PathBuf};
+use std::{fmt, str};
-/// The contents of `LICENSE-APACHE.txt`, the text of the Apache License, version 2.0.
-pub(crate) static LICENSE_APACHE: &[u8] = include_bytes!("static/LICENSE-APACHE.txt");
-
-/// The contents of `LICENSE-MIT.txt`, the text of the MIT License.
-pub(crate) static LICENSE_MIT: &[u8] = include_bytes!("static/LICENSE-MIT.txt");
-
-/// The contents of `rust-logo.svg`, the default icon of the documentation.
-pub(crate) static RUST_LOGO_SVG: &[u8] = include_bytes!("static/images/rust-logo.svg");
-
-/// The default documentation favicons (SVG and PNG fallbacks)
-pub(crate) static RUST_FAVICON_SVG: &[u8] = include_bytes!("static/images/favicon.svg");
-pub(crate) static RUST_FAVICON_PNG_16: &[u8] = include_bytes!("static/images/favicon-16x16.png");
-pub(crate) static RUST_FAVICON_PNG_32: &[u8] = include_bytes!("static/images/favicon-32x32.png");
-
-/// The built-in themes given to every documentation site.
-pub(crate) mod themes {
- /// The "light" theme, selected by default when no setting is available. Used as the basis for
- /// the `--check-theme` functionality.
- pub(crate) static LIGHT: &str = include_str!("static/css/themes/light.css");
-
- /// The "dark" theme.
- pub(crate) static DARK: &str = include_str!("static/css/themes/dark.css");
-
- /// The "ayu" theme.
- pub(crate) static AYU: &str = include_str!("static/css/themes/ayu.css");
+pub(crate) struct StaticFile {
+ pub(crate) filename: PathBuf,
+ pub(crate) bytes: &'static [u8],
}
-/// Files related to the Fira Sans font.
-pub(crate) mod fira_sans {
- /// The file `FiraSans-Regular.woff2`, the Regular variant of the Fira Sans font in woff2.
- pub(crate) static REGULAR: &[u8] = include_bytes!("static/fonts/FiraSans-Regular.woff2");
-
- /// The file `FiraSans-Medium.woff2`, the Medium variant of the Fira Sans font in woff2.
- pub(crate) static MEDIUM: &[u8] = include_bytes!("static/fonts/FiraSans-Medium.woff2");
-
- /// The file `FiraSans-LICENSE.txt`, the license text for the Fira Sans font.
- pub(crate) static LICENSE: &[u8] = include_bytes!("static/fonts/FiraSans-LICENSE.txt");
+impl StaticFile {
+ fn new(filename: &str, bytes: &'static [u8]) -> StaticFile {
+ Self { filename: static_filename(filename, bytes), bytes }
+ }
+
+ pub(crate) fn minified(&self) -> Vec<u8> {
+ if self.filename.ends_with(".css") {
+ minifier::css::minify(str::from_utf8(self.bytes).unwrap()).unwrap().to_string().into()
+ } else if self.filename.ends_with(".js") {
+ minifier::js::minify(str::from_utf8(self.bytes).unwrap()).to_string().into()
+ } else {
+ self.bytes.to_owned()
+ }
+ }
+
+ pub(crate) fn output_filename(&self) -> &Path {
+ &self.filename
+ }
}
-/// Files related to the Source Serif 4 font.
-pub(crate) mod source_serif_4 {
- /// The file `SourceSerif4-Regular.ttf.woff2`, the Regular variant of the Source Serif 4 font in
- /// woff2.
- pub(crate) static REGULAR: &[u8] =
- include_bytes!("static/fonts/SourceSerif4-Regular.ttf.woff2");
-
- /// The file `SourceSerif4-Bold.ttf.woff2`, the Bold variant of the Source Serif 4 font in
- /// woff2.
- pub(crate) static BOLD: &[u8] = include_bytes!("static/fonts/SourceSerif4-Bold.ttf.woff2");
-
- /// The file `SourceSerif4-It.ttf.woff2`, the Italic variant of the Source Serif 4 font in
- /// woff2.
- pub(crate) static ITALIC: &[u8] = include_bytes!("static/fonts/SourceSerif4-It.ttf.woff2");
-
- /// The file `SourceSerif4-LICENSE.txt`, the license text for the Source Serif 4 font.
- pub(crate) static LICENSE: &[u8] = include_bytes!("static/fonts/SourceSerif4-LICENSE.md");
+/// The Display implementation for a StaticFile outputs its filename. This makes it
+/// convenient to interpolate static files into HTML templates.
+impl fmt::Display for StaticFile {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "{}", self.output_filename().display())
+ }
}
-/// Files related to the Source Code Pro font.
-pub(crate) mod source_code_pro {
- /// The file `SourceCodePro-Regular.ttf.woff2`, the Regular variant of the Source Code Pro font
- /// in woff2.
- pub(crate) static REGULAR: &[u8] =
- include_bytes!("static/fonts/SourceCodePro-Regular.ttf.woff2");
-
- /// The file `SourceCodePro-Semibold.ttf.woff2`, the Semibold variant of the Source Code Pro
- /// font in woff2.
- pub(crate) static SEMIBOLD: &[u8] =
- include_bytes!("static/fonts/SourceCodePro-Semibold.ttf.woff2");
-
- /// The file `SourceCodePro-It.ttf.woff2`, the Italic variant of the Source Code Pro font in
- /// woff2.
- pub(crate) static ITALIC: &[u8] = include_bytes!("static/fonts/SourceCodePro-It.ttf.woff2");
+/// Insert the provided suffix into a filename just before the extension.
+pub(crate) fn suffix_path(filename: &str, suffix: &str) -> PathBuf {
+ // We use splitn vs Path::extension here because we might get a filename
+ // like `style.min.css` and we want to process that into
+ // `style-suffix.min.css`. Path::extension would just return `css`
+ // which would result in `style.min-suffix.css` which isn't what we
+ // want.
+ let (base, ext) = filename.split_once('.').unwrap();
+ let filename = format!("{}{}.{}", base, suffix, ext);
+ filename.into()
+}
- /// The file `SourceCodePro-LICENSE.txt`, the license text of the Source Code Pro font.
- pub(crate) static LICENSE: &[u8] = include_bytes!("static/fonts/SourceCodePro-LICENSE.txt");
+pub(crate) fn static_filename(filename: &str, contents: &[u8]) -> PathBuf {
+ let filename = filename.rsplit("/").next().unwrap();
+ suffix_path(filename, &static_suffix(contents))
}
-/// Files related to the Nanum Barun Gothic font.
-///
-/// These files are used to avoid some legacy CJK serif fonts in Windows.
-///
-/// Note that the Noto Sans KR font, which was used previously but was not very readable on Windows,
-/// has been replaced by the Nanum Barun Gothic font. This is due to Windows' implementation of font
-/// rendering that distorts OpenType fonts too much.
-///
-/// The font files were generated with these commands:
-///
-/// ```sh
-/// pyftsubset NanumBarunGothic.ttf \
-/// --unicodes=U+AC00-D7AF,U+1100-11FF,U+3130-318F,U+A960-A97F,U+D7B0-D7FF \
-/// --output-file=NanumBarunGothic.ttf.woff2 --flavor=woff2
-/// ```
-pub(crate) mod nanum_barun_gothic {
- /// The file `NanumBarunGothic.ttf.woff2`, the Regular variant of the Nanum Barun Gothic font.
- pub(crate) static REGULAR: &[u8] = include_bytes!("static/fonts/NanumBarunGothic.ttf.woff2");
+fn static_suffix(bytes: &[u8]) -> String {
+ let mut hasher = FxHasher::default();
+ hasher.write(bytes);
+ format!("-{:016x}", hasher.finish())
+}
- /// The file `NanumBarunGothic-LICENSE.txt`, the license text of the Nanum Barun Gothic font.
- pub(crate) static LICENSE: &[u8] = include_bytes!("static/fonts/NanumBarunGothic-LICENSE.txt");
+macro_rules! static_files {
+ ($($field:ident => $file_path:literal,)+) => {
+ pub(crate) struct StaticFiles {
+ $(pub $field: StaticFile,)+
+ }
+
+ pub(crate) static STATIC_FILES: std::sync::LazyLock<StaticFiles> = std::sync::LazyLock::new(|| StaticFiles {
+ $($field: StaticFile::new($file_path, include_bytes!($file_path)),)+
+ });
+
+ pub(crate) fn for_each<E>(f: impl Fn(&StaticFile) -> Result<(), E>) -> Result<(), E> {
+ for sf in [
+ $(&STATIC_FILES.$field,)+
+ ] {
+ f(sf)?
+ }
+ Ok(())
+ }
+ }
}
-/// Files related to the sidebar in rustdoc sources.
-pub(crate) mod sidebar {
- /// File script to handle sidebar.
- pub(crate) static SOURCE_SCRIPT: &str = include_str!("static/js/source-script.js");
+static_files! {
+ rustdoc_css => "static/css/rustdoc.css",
+ settings_css => "static/css/settings.css",
+ noscript_css => "static/css/noscript.css",
+ normalize_css => "static/css/normalize.css",
+ main_js => "static/js/main.js",
+ search_js => "static/js/search.js",
+ settings_js => "static/js/settings.js",
+ source_script_js => "static/js/source-script.js",
+ storage_js => "static/js/storage.js",
+ scrape_examples_js => "static/js/scrape-examples.js",
+ wheel_svg => "static/images/wheel.svg",
+ clipboard_svg => "static/images/clipboard.svg",
+ down_arrow_svg => "static/images/down-arrow.svg",
+ toggle_minus_png => "static/images/toggle-minus.svg",
+ toggle_plus_png => "static/images/toggle-plus.svg",
+ copyright => "static/COPYRIGHT.txt",
+ license_apache => "static/LICENSE-APACHE.txt",
+ license_mit => "static/LICENSE-MIT.txt",
+ rust_logo_svg => "static/images/rust-logo.svg",
+ rust_favicon_svg => "static/images/favicon.svg",
+ rust_favicon_png_16 => "static/images/favicon-16x16.png",
+ rust_favicon_png_32 => "static/images/favicon-32x32.png",
+ theme_light_css => "static/css/themes/light.css",
+ theme_dark_css => "static/css/themes/dark.css",
+ theme_ayu_css => "static/css/themes/ayu.css",
+ fira_sans_regular => "static/fonts/FiraSans-Regular.woff2",
+ fira_sans_medium => "static/fonts/FiraSans-Medium.woff2",
+ fira_sans_license => "static/fonts/FiraSans-LICENSE.txt",
+ source_serif_4_regular => "static/fonts/SourceSerif4-Regular.ttf.woff2",
+ source_serif_4_bold => "static/fonts/SourceSerif4-Bold.ttf.woff2",
+ source_serif_4_italic => "static/fonts/SourceSerif4-It.ttf.woff2",
+ source_serif_4_license => "static/fonts/SourceSerif4-LICENSE.md",
+ source_code_pro_regular => "static/fonts/SourceCodePro-Regular.ttf.woff2",
+ source_code_pro_semibold => "static/fonts/SourceCodePro-Semibold.ttf.woff2",
+ source_code_pro_italic => "static/fonts/SourceCodePro-It.ttf.woff2",
+ source_code_pro_license => "static/fonts/SourceCodePro-LICENSE.txt",
+ nanum_barun_gothic_regular => "static/fonts/NanumBarunGothic.ttf.woff2",
+ nanum_barun_gothic_license => "static/fonts/NanumBarunGothic-LICENSE.txt",
}
+
+pub(crate) static SCRAPE_EXAMPLES_HELP_MD: &str = include_str!("static/js/scrape-examples.js");
<meta name="description" content="{{page.description}}"> {#- -#}
<meta name="keywords" content="{{page.keywords}}"> {#- -#}
<title>{{page.title}}</title> {#- -#}
- <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}SourceSerif4-Regular.ttf.woff2"> {#- -#}
- <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}FiraSans-Regular.woff2"> {#- -#}
- <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}FiraSans-Medium.woff2"> {#- -#}
- <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}SourceCodePro-Regular.ttf.woff2"> {#- -#}
- <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}SourceSerif4-Bold.ttf.woff2"> {#- -#}
- <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}SourceCodePro-Semibold.ttf.woff2"> {#- -#}
+ <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.source_serif_4_regular}}"> {#- -#}
+ <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.fira_sans_regular}}"> {#- -#}
+ <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.fira_sans_medium}}"> {#- -#}
+ <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.source_code_pro_regular}}"> {#- -#}
+ <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.source_serif_4_bold}}"> {#- -#}
+ <link rel="preload" as="font" type="font/woff2" crossorigin href="{{static_root_path|safe}}{{files.source_code_pro_semibold}}"> {#- -#}
<link rel="stylesheet" {# -#}
- href="{{static_root_path|safe}}normalize{{page.resource_suffix}}.css"> {#- -#}
+ href="{{static_root_path|safe}}{{files.normalize_css}}"> {#- -#}
<link rel="stylesheet" {# -#}
- href="{{static_root_path|safe}}rustdoc{{page.resource_suffix}}.css" {# -#}
+ href="{{static_root_path|safe}}{{files.rustdoc_css}}" {# -#}
id="mainThemeStyle"> {#- -#}
+ <link rel="stylesheet" id="themeStyle" href="{{static_root_path|safe}}{{files.theme_light_css}}"> {#- -#}
+ <link rel="stylesheet" disabled href="{{static_root_path|safe}}{{files.theme_dark_css}}"> {#- -#}
+ <link rel="stylesheet" disabled href="{{static_root_path|safe}}{{files.theme_ayu_css}}"> {#- -#}
{%- for theme in themes -%}
- <link rel="stylesheet" {# -#}
- href="{{static_root_path|safe}}{{theme}}{{page.resource_suffix}}.css" {# -#}
- {%- if theme == "light" -%}
- id="themeStyle"
- {%- else -%}
- disabled
- {%- endif -%}
- >
+ <link rel="stylesheet" disabled href="{{page.root_path|safe}}{{theme}}{{page.resource_suffix}}.css"> {#- -#}
{%- endfor -%}
<script id="default-settings" {# -#}
{% for (k, v) in layout.default_settings %}
data-{{k}}="{{v}}"
{%- endfor -%}
></script> {#- -#}
- <script src="{{static_root_path|safe}}storage{{page.resource_suffix}}.js"></script> {#- -#}
+ <script src="{{static_root_path|safe}}{{files.storage_js}}"></script> {#- -#}
{%- if page.css_class.contains("crate") -%}
<script defer src="{{page.root_path|safe}}crates{{page.resource_suffix}}.js"></script> {#- -#}
{%- else if page.css_class == "source" -%}
- <script defer src="{{static_root_path|safe}}source-script{{page.resource_suffix}}.js"></script> {#- -#}
+ <script defer src="{{static_root_path|safe}}{{files.source_script_js}}"></script> {#- -#}
<script defer src="{{page.root_path|safe}}source-files{{page.resource_suffix}}.js"></script> {#- -#}
{%- else if !page.css_class.contains("mod") -%}
<script defer src="sidebar-items{{page.resource_suffix}}.js"></script> {#- -#}
{%- endif -%}
- <script defer src="{{static_root_path|safe}}main{{page.resource_suffix}}.js"></script> {#- -#}
+ <script defer src="{{static_root_path|safe}}{{files.main_js}}"></script> {#- -#}
{%- if layout.scrape_examples_extension -%}
- <script defer src="{{page.root_path|safe}}scrape-examples{{page.resource_suffix}}.js"></script> {#- -#}
+ <script defer src="{{page.root_path|safe}}{{files.scrape_examples_js}}"></script> {#- -#}
{%- endif -%}
<noscript> {#- -#}
<link rel="stylesheet" {# -#}
- href="{{static_root_path|safe}}noscript{{page.resource_suffix}}.css"> {#- -#}
+ href="{{static_root_path|safe}}{{files.noscript_css}}"> {#- -#}
</noscript> {#- -#}
{%- if layout.css_file_extension.is_some() -%}
<link rel="stylesheet" {# -#}
<link rel="icon" href="{{layout.favicon}}"> {#- -#}
{%- else -%}
<link rel="alternate icon" type="image/png" {# -#}
- href="{{static_root_path|safe}}favicon-16x16{{page.resource_suffix}}.png"> {#- -#}
+ href="{{static_root_path|safe}}{{files.rust_favicon_png_16}}"> {#- -#}
<link rel="alternate icon" type="image/png" {# -#}
- href="{{static_root_path|safe}}favicon-32x32{{page.resource_suffix}}.png"> {#- -#}
+ href="{{static_root_path|safe}}{{files.rust_favicon_png_32}}"> {#- -#}
<link rel="icon" type="image/svg+xml" {# -#}
- href="{{static_root_path|safe}}favicon{{page.resource_suffix}}.svg"> {#- -#}
+ href="{{static_root_path|safe}}{{files.rust_favicon_svg}}"> {#- -#}
{%- endif -%}
{{- layout.external_html.in_header|safe -}}
</head> {#- -#}
{%- if !layout.logo.is_empty() -%}
<img src="{{layout.logo}}" alt="logo"> {#- -#}
{%- else -%}
- <img class="rust-logo" src="{{static_root_path|safe}}rust-logo{{page.resource_suffix}}.svg" alt="logo"> {#- -#}
+ <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {#- -#}
{%- endif -%}
</div> {#- -#}
</a> {#- -#}
{%- if !layout.logo.is_empty() %}
<img src="{{layout.logo}}" alt="logo"> {#- -#}
{%- else -%}
- <img class="rust-logo" src="{{static_root_path|safe}}rust-logo{{page.resource_suffix}}.svg" alt="logo"> {#- -#}
+ <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {#- -#}
{%- endif -%}
</div> {#- -#}
</a> {#- -#}
{%- if !layout.logo.is_empty() %}
<img src="{{layout.logo}}" alt="logo"> {#- -#}
{%- else -%}
- <img class="rust-logo" src="{{static_root_path|safe}}rust-logo{{page.resource_suffix}}.svg" alt="logo"> {#- -#}
+ <img class="rust-logo" src="{{static_root_path|safe}}{{files.rust_logo_svg}}" alt="logo"> {#- -#}
{%- endif -%}
</a> {#- -#}
{%- endif -%}
<form class="search-form"> {#- -#}
- <div class="search-container"> {#- -#}
- <span></span> {#- This empty span is a hacky fix for Safari - See #93184 -#}
- <input {# -#}
- class="search-input" {# -#}
- name="search" {# -#}
- autocomplete="off" {# -#}
- spellcheck="false" {# -#}
- placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#}
- type="search"> {#- -#}
- <div id="help-button" title="help" tabindex="-1"> {#- -#}
- <a href="{{page.root_path|safe}}help.html">?</a> {#- -#}
- </div> {#- -#}
- <div id="settings-menu" tabindex="-1"> {#- -#}
- <a href="{{page.root_path|safe}}settings.html" title="settings"> {#- -#}
- <img width="22" height="22" alt="Change settings" {# -#}
- src="{{static_root_path|safe}}wheel{{page.resource_suffix}}.svg"> {#- -#}
- </a> {#- -#}
- </div> {#- -#}
+ <span></span> {#- This empty span is a hacky fix for Safari - See #93184 -#}
+ <input {# -#}
+ class="search-input" {# -#}
+ name="search" {# -#}
+ autocomplete="off" {# -#}
+ spellcheck="false" {# -#}
+ placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#}
+ type="search"> {#- -#}
+ <div id="help-button" title="help" tabindex="-1"> {#- -#}
+ <a href="{{page.root_path|safe}}help.html">?</a> {#- -#}
+ </div> {#- -#}
+ <div id="settings-menu" tabindex="-1"> {#- -#}
+ <a href="{{page.root_path|safe}}settings.html" title="settings"> {#- -#}
+ <img width="22" height="22" alt="Change settings" {# -#}
+ src="{{static_root_path|safe}}{{files.wheel_svg}}"> {#- -#}
+ </a> {#- -#}
</div> {#- -#}
</form> {#- -#}
</nav> {#- -#}
{{- layout.external_html.after_content|safe -}}
<div id="rustdoc-vars" {# -#}
data-root-path="{{page.root_path|safe}}" {# -#}
+ data-static-root-path="{{static_root_path|safe}}" {# -#}
data-current-crate="{{layout.krate}}" {# -#}
data-themes="{{themes|join(",") }}" {# -#}
data-resource-suffix="{{page.resource_suffix}}" {# -#}
data-rustdoc-version="{{rustdoc_version}}" {# -#}
+ data-search-js="{{files.search_js}}" {# -#}
+ data-settings-js="{{files.settings_js}}" {# -#}
+ data-settings-css="{{files.settings_css}}" {# -#}
> {#- -#}
</div> {#- -#}
</body> {#- -#}
{%- endfor -%}
<a class="{{item_type}}" href="#">{{name}}</a> {#- -#}
<button id="copy-path" onclick="copy_path(this)" title="Copy item path to clipboard"> {#- -#}
- <img src="{{static_root_path|safe}}clipboard{{page.resource_suffix}}.svg" {# -#}
+ <img src="{{static_root_path|safe}}{{clipboard_svg}}" {# -#}
width="19" height="18" {# -#}
alt="Copy item path"> {#- -#}
</button> {#- -#}
<a class="srclink" href="{{href|safe}}">source</a> · {# -#}
{%- else -%}
{%- endmatch -%}
- <a id="toggle-all-docs" href="javascript:void(0)" title="collapse all docs"> {#- -#}
- [<span class="inner">−</span>] {#- -#}
- </a> {#- -#}
+ <button id="toggle-all-docs" title="collapse all docs"> {#- -#}
+ [<span>−</span>] {#- -#}
+ </button> {#- -#}
</span> {#- -#}
</div> {#- -#}
.map(rustc_ast_pretty::pprust::attribute_to_string)
.collect();
let span = item.span(self.tcx);
- let clean::Item { name, attrs: _, kind: _, visibility, item_id, cfg: _ } = item;
+ let visibility = item.visibility(self.tcx);
+ let clean::Item { name, attrs: _, kind: _, item_id, cfg: _, .. } = item;
let inner = match *item.kind {
clean::KeywordItem => return None,
clean::StrippedItem(ref inner) => {
}
}
- fn convert_visibility(&self, v: clean::Visibility) -> Visibility {
- use clean::Visibility::*;
+ fn convert_visibility(&self, v: Option<ty::Visibility<DefId>>) -> Visibility {
match v {
- Public => Visibility::Public,
- Inherited => Visibility::Default,
- Restricted(did) if did.is_crate_root() => Visibility::Crate,
- Restricted(did) => Visibility::Restricted {
+ None => Visibility::Default,
+ Some(ty::Visibility::Public) => Visibility::Public,
+ Some(ty::Visibility::Restricted(did)) if did.is_crate_root() => Visibility::Crate,
+ Some(ty::Visibility::Restricted(did)) => Visibility::Restricted {
parent: from_item_id(did.into(), self.tcx),
path: self.tcx.def_path(did).to_string_no_crate_verbose(),
},
ItemEnum::AssocConst { type_: ty.into_tcx(tcx), default: Some(default.expr(tcx)) }
}
TyAssocTypeItem(g, b) => ItemEnum::AssocType {
- generics: (*g).into_tcx(tcx),
+ generics: g.into_tcx(tcx),
bounds: b.into_tcx(tcx),
default: None,
},
BareFunction(f) => Type::FunctionPointer(Box::new((*f).into_tcx(tcx))),
Tuple(t) => Type::Tuple(t.into_tcx(tcx)),
Slice(t) => Type::Slice(Box::new((*t).into_tcx(tcx))),
- Array(t, s) => Type::Array { type_: Box::new((*t).into_tcx(tcx)), len: s },
+ Array(t, s) => Type::Array { type_: Box::new((*t).into_tcx(tcx)), len: s.to_string() },
ImplTrait(g) => Type::ImplTrait(g.into_tcx(tcx)),
Infer => Type::Infer,
RawPointer(mutability, type_) => Type::RawPointer {
stable("json", |o| {
o.optopt("", "json", "Configure the structure of JSON diagnostics", "CONFIG")
}),
- unstable("disable-minification", |o| {
- o.optflagmulti("", "disable-minification", "Disable minification applied on JS files")
- }),
stable("allow", |o| o.optmulti("A", "allow", "Set lint allowed", "LINT")),
stable("warn", |o| o.optmulti("W", "warn", "Set lint warnings", "LINT")),
stable("force-warn", |o| o.optmulti("", "force-warn", "Set lint force-warn", "LINT")),
)
}),
// deprecated / removed options
+ unstable("disable-minification", |o| o.optflagmulti("", "disable-minification", "removed")),
stable("plugin-path", |o| {
o.optmulti(
"",
}
pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) -> bool {
- if !cx.cache.access_levels.is_public(item.item_id.expect_def_id())
+ if !cx.cache.effective_visibilities.is_directly_public(cx.tcx, item.item_id.expect_def_id())
|| matches!(
*item.kind,
clean::StructFieldItem(_)
);
}
} else if tests.found_tests > 0
- && !cx.cache.access_levels.is_exported(item.item_id.expect_def_id())
+ && !cx.cache.effective_visibilities.is_exported(cx.tcx, item.item_id.expect_def_id())
{
cx.tcx.struct_span_lint_hir(
crate::lint::PRIVATE_DOC_TESTS,
})
.and_then(|self_id| match tcx.def_kind(self_id) {
DefKind::Impl => self.def_id_to_res(self_id),
+ DefKind::Use => None,
def_kind => Some(Res::Def(def_kind, self_id)),
})
}
item.item_id.expect_def_id().as_local().map(|src_id| (src_id, dst_id))
})
{
- if self.cx.tcx.privacy_access_levels(()).is_exported(src_id)
- && !self.cx.tcx.privacy_access_levels(()).is_exported(dst_id)
+ if self.cx.tcx.effective_visibilities(()).is_exported(src_id)
+ && !self.cx.tcx.effective_visibilities(()).is_exported(dst_id)
{
privacy_error(self.cx, diag_info, path_str);
}
// Otherwise, it must be an associated item or variant
let res = partial_res.expect("None case was handled by `last_found_module`");
- let name = res.name(tcx);
let kind = match res {
Res::Def(kind, _) => Some(kind),
Res::Primitive(_) => None,
} else {
"associated item"
};
+ let name = res.name(tcx);
let note = format!(
"the {} `{}` has no {} named `{}`",
res.descr(),
diag_info.link_range = disambiguator_range;
report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, _sp| {
let msg = format!(
- "see {}/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators",
+ "see {}/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators",
crate::DOC_RUST_LANG_ORG_CHANNEL
);
diag.note(&msg);
}
drop_tag(tags, tag_name, r, f);
} else {
- tags.push((tag_name, r));
+ let mut is_self_closing = false;
+ let mut quote_pos = None;
+ if c != '>' {
+ let mut quote = None;
+ let mut after_eq = false;
+ for (i, c) in text[pos..].char_indices() {
+ if !c.is_whitespace() {
+ if let Some(q) = quote {
+ if c == q {
+ quote = None;
+ quote_pos = None;
+ after_eq = false;
+ }
+ } else if c == '>' {
+ break;
+ } else if c == '/' && !after_eq {
+ is_self_closing = true;
+ } else {
+ if is_self_closing {
+ is_self_closing = false;
+ }
+ if (c == '"' || c == '\'') && after_eq {
+ quote = Some(c);
+ quote_pos = Some(pos + i);
+ } else if c == '=' {
+ after_eq = true;
+ }
+ }
+ } else if quote.is_none() {
+ after_eq = false;
+ }
+ }
+ }
+ if let Some(quote_pos) = quote_pos {
+ let qr = Range { start: quote_pos, end: quote_pos };
+ f(
+ &format!("unclosed quoted HTML attribute on tag `{}`", tag_name),
+ &qr,
+ false,
+ );
+ }
+ if is_self_closing {
+ // https://html.spec.whatwg.org/#parse-error-non-void-html-element-start-tag-with-trailing-solidus
+ let valid = ALLOWED_UNCLOSED.contains(&&tag_name[..])
+ || tags.iter().take(pos + 1).any(|(at, _)| {
+ let at = at.to_lowercase();
+ at == "svg" || at == "math"
+ });
+ if !valid {
+ f(&format!("invalid self-closing HTML tag `{}`", tag_name), &r, false);
+ }
+ } else {
+ tags.push((tag_name, r));
+ }
}
}
break;
// strip all impls referencing stripped items
let mut stripper = ImplStripper {
+ tcx: cx.tcx,
retained: &retained,
cache: &cx.cache,
is_json_output,
description: "strips all private import statements (`use`, `extern crate`) from a crate",
};
-pub(crate) fn strip_priv_imports(krate: clean::Crate, _: &mut DocContext<'_>) -> clean::Crate {
- ImportStripper.fold_crate(krate)
+pub(crate) fn strip_priv_imports(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
+ ImportStripper { tcx: cx.tcx }.fold_crate(krate)
}
{
let mut stripper = Stripper {
retained: &mut retained,
- access_levels: &cx.cache.access_levels,
+ effective_visibilities: &cx.cache.effective_visibilities,
update_retained: true,
is_json_output,
+ tcx: cx.tcx,
};
- krate = ImportStripper.fold_crate(stripper.fold_crate(krate));
+ krate = ImportStripper { tcx: cx.tcx }.fold_crate(stripper.fold_crate(krate));
}
// strip all impls referencing private items
let mut stripper = ImplStripper {
+ tcx: cx.tcx,
retained: &retained,
cache: &cx.cache,
is_json_output,
//! A collection of utility functions for the `strip_*` passes.
use rustc_hir::def_id::DefId;
-use rustc_middle::middle::privacy::AccessLevels;
+use rustc_middle::ty::{TyCtxt, Visibility};
+use rustc_span::symbol::sym;
use std::mem;
-use crate::clean::{self, Item, ItemId, ItemIdSet};
+use crate::clean::{self, Item, ItemId, ItemIdSet, NestedAttributesExt};
use crate::fold::{strip_item, DocFolder};
use crate::formats::cache::Cache;
+use crate::visit_lib::RustdocEffectiveVisibilities;
-pub(crate) struct Stripper<'a> {
+pub(crate) struct Stripper<'a, 'tcx> {
pub(crate) retained: &'a mut ItemIdSet,
- pub(crate) access_levels: &'a AccessLevels<DefId>,
+ pub(crate) effective_visibilities: &'a RustdocEffectiveVisibilities,
pub(crate) update_retained: bool,
pub(crate) is_json_output: bool,
+ pub(crate) tcx: TyCtxt<'tcx>,
}
// We need to handle this differently for the JSON output because some non exported items could
// are in the public API, which is not enough.
#[inline]
fn is_item_reachable(
+ tcx: TyCtxt<'_>,
is_json_output: bool,
- access_levels: &AccessLevels<DefId>,
+ effective_visibilities: &RustdocEffectiveVisibilities,
item_id: ItemId,
) -> bool {
if is_json_output {
- access_levels.is_reachable(item_id.expect_def_id())
+ effective_visibilities.is_reachable(tcx, item_id.expect_def_id())
} else {
- access_levels.is_exported(item_id.expect_def_id())
+ effective_visibilities.is_exported(tcx, item_id.expect_def_id())
}
}
-impl<'a> DocFolder for Stripper<'a> {
+impl<'a, 'tcx> DocFolder for Stripper<'a, 'tcx> {
fn fold_item(&mut self, i: Item) -> Option<Item> {
match *i.kind {
clean::StrippedItem(..) => {
| clean::ForeignTypeItem => {
let item_id = i.item_id;
if item_id.is_local()
- && !is_item_reachable(self.is_json_output, self.access_levels, item_id)
+ && !is_item_reachable(
+ self.tcx,
+ self.is_json_output,
+ self.effective_visibilities,
+ item_id,
+ )
{
debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name);
return None;
}
clean::StructFieldItem(..) => {
- if !i.visibility.is_public() {
+ if i.visibility(self.tcx) != Some(Visibility::Public) {
return Some(strip_item(i));
}
}
clean::ModuleItem(..) => {
- if i.item_id.is_local() && !i.visibility.is_public() {
+ if i.item_id.is_local() && i.visibility(self.tcx) != Some(Visibility::Public) {
debug!("Stripper: stripping module {:?}", i.name);
let old = mem::replace(&mut self.update_retained, false);
let ret = strip_item(self.fold_item_recur(i));
}
/// This stripper discards all impls which reference stripped items
-pub(crate) struct ImplStripper<'a> {
+pub(crate) struct ImplStripper<'a, 'tcx> {
+ pub(crate) tcx: TyCtxt<'tcx>,
pub(crate) retained: &'a ItemIdSet,
pub(crate) cache: &'a Cache,
pub(crate) is_json_output: bool,
pub(crate) document_private: bool,
}
-impl<'a> DocFolder for ImplStripper<'a> {
+impl<'a> ImplStripper<'a, '_> {
+ #[inline]
+ fn should_keep_impl(&self, item: &Item, for_def_id: DefId) -> bool {
+ if !for_def_id.is_local() || self.retained.contains(&for_def_id.into()) {
+ true
+ } else if self.is_json_output {
+ // If the "for" item is exported and the impl block isn't `#[doc(hidden)]`, then we
+ // need to keep it.
+ self.cache.effective_visibilities.is_exported(self.tcx, for_def_id)
+ && !item.attrs.lists(sym::doc).has_word(sym::hidden)
+ } else {
+ false
+ }
+ }
+}
+
+impl<'a> DocFolder for ImplStripper<'a, '_> {
fn fold_item(&mut self, i: Item) -> Option<Item> {
if let clean::ImplItem(ref imp) = *i.kind {
// Impl blocks can be skipped if they are: empty; not a trait impl; and have no
let item_id = i.item_id;
item_id.is_local()
&& !is_item_reachable(
+ self.tcx,
self.is_json_output,
- &self.cache.access_levels,
+ &self.cache.effective_visibilities,
item_id,
)
})
return None;
}
}
+ // Because we don't inline in `maybe_inline_local` if the output format is JSON,
+ // we need to make a special check for JSON output: we want to keep it unless it has
+ // a `#[doc(hidden)]` attribute if the `for_` type is exported.
if let Some(did) = imp.for_.def_id(self.cache) {
- if did.is_local() && !imp.for_.is_assoc_ty() && !self.retained.contains(&did.into())
- {
+ if !imp.for_.is_assoc_ty() && !self.should_keep_impl(&i, did) {
debug!("ImplStripper: impl item for stripped type; removing");
return None;
}
}
if let Some(did) = imp.trait_.as_ref().map(|t| t.def_id()) {
- if did.is_local() && !self.retained.contains(&did.into()) {
+ if !self.should_keep_impl(&i, did) {
debug!("ImplStripper: impl item for stripped trait; removing");
return None;
}
if let Some(generics) = imp.trait_.as_ref().and_then(|t| t.generics()) {
for typaram in generics {
if let Some(did) = typaram.def_id(self.cache) {
- if did.is_local() && !self.retained.contains(&did.into()) {
+ if !self.should_keep_impl(&i, did) {
debug!(
"ImplStripper: stripped item in trait's generics; removing impl"
);
}
/// This stripper discards all private import statements (`use`, `extern crate`)
-pub(crate) struct ImportStripper;
+pub(crate) struct ImportStripper<'tcx> {
+ pub(crate) tcx: TyCtxt<'tcx>,
+}
-impl DocFolder for ImportStripper {
+impl<'tcx> DocFolder for ImportStripper<'tcx> {
fn fold_item(&mut self, i: Item) -> Option<Item> {
match *i.kind {
- clean::ExternCrateItem { .. } | clean::ImportItem(..) if !i.visibility.is_public() => {
+ clean::ExternCrateItem { .. } | clean::ImportItem(..)
+ if i.visibility(self.tcx) != Some(Visibility::Public) =>
+ {
None
}
_ => Some(self.fold_item_recur(i)),
use rustc_hir::def_id::DefId;
use rustc_hir::Node;
use rustc_hir::CRATE_HIR_ID;
-use rustc_middle::middle::privacy::AccessLevel;
-use rustc_middle::ty::{TyCtxt, Visibility};
+use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::Span;
use std::mem;
-use crate::clean::{self, cfg::Cfg, AttributesExt, NestedAttributesExt};
+use crate::clean::{cfg::Cfg, AttributesExt, NestedAttributesExt};
use crate::core;
/// This module is used to store stuff from Rust's AST in a more convenient
pub(crate) where_inner: Span,
pub(crate) mods: Vec<Module<'hir>>,
pub(crate) id: hir::HirId,
- // (item, renamed)
- pub(crate) items: Vec<(&'hir hir::Item<'hir>, Option<Symbol>)>,
+ // (item, renamed, import_id)
+ pub(crate) items: Vec<(&'hir hir::Item<'hir>, Option<Symbol>, Option<hir::HirId>)>,
pub(crate) foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option<Symbol>)>,
}
hir::CRATE_HIR_ID,
self.cx.tcx.hir().root_module(),
self.cx.tcx.crate_name(LOCAL_CRATE),
+ None,
);
// `#[macro_export] macro_rules!` items are reexported at the top level of the
if self.cx.tcx.has_attr(def_id, sym::macro_export) {
if inserted.insert(def_id) {
let item = self.cx.tcx.hir().expect_item(local_def_id);
- top_level_module.items.push((item, None));
+ top_level_module.items.push((item, None, None));
}
}
}
id: hir::HirId,
m: &'tcx hir::Mod<'tcx>,
name: Symbol,
+ parent_id: Option<hir::HirId>,
) -> Module<'tcx> {
let mut om = Module::new(name, id, m.spans.inner_span);
let def_id = self.cx.tcx.hir().local_def_id(id).to_def_id();
if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
continue;
}
- self.visit_item(item, None, &mut om);
+ self.visit_item(item, None, &mut om, parent_id);
}
for &i in m.item_ids {
let item = self.cx.tcx.hir().item(i);
// Later passes in rustdoc will de-duplicate by name and kind, so if glob-
// imported items appear last, then they'll be the ones that get discarded.
if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) {
- self.visit_item(item, None, &mut om);
+ self.visit_item(item, None, &mut om, parent_id);
}
}
self.inside_public_path = orig_inside_public_path;
// made reachable by cross-crate inlining which we're checking here.
// (this is done here because we need to know this upfront).
if !res_did.is_local() && !is_no_inline {
- let attrs = clean::inline::load_attrs(self.cx, res_did);
- let self_is_hidden = attrs.lists(sym::doc).has_word(sym::hidden);
- if !self_is_hidden {
- if let Res::Def(kind, did) = res {
- if kind == DefKind::Mod {
- crate::visit_lib::LibEmbargoVisitor::new(self.cx).visit_mod(did)
- } else {
- // All items need to be handled here in case someone wishes to link
- // to them with intra-doc links
- self.cx.cache.access_levels.set_access_level(
- did,
- || Visibility::Restricted(CRATE_DEF_ID),
- AccessLevel::Public,
- );
- }
- }
- }
+ crate::visit_lib::lib_embargo_visit_item(self.cx, res_did);
return false;
}
None => return false,
};
- let is_private = !self.cx.cache.access_levels.is_public(res_did);
+ let is_private =
+ !self.cx.cache.effective_visibilities.is_directly_public(self.cx.tcx, res_did);
let is_hidden = inherits_doc_hidden(self.cx.tcx, res_hir_id);
// Only inline if requested or if the item would otherwise be stripped.
let prev = mem::replace(&mut self.inlining, true);
for &i in m.item_ids {
let i = self.cx.tcx.hir().item(i);
- self.visit_item(i, None, om);
+ self.visit_item(i, None, om, Some(id));
}
self.inlining = prev;
true
}
Node::Item(it) if !glob => {
let prev = mem::replace(&mut self.inlining, true);
- self.visit_item(it, renamed, om);
+ self.visit_item(it, renamed, om, Some(id));
self.inlining = prev;
true
}
item: &'tcx hir::Item<'_>,
renamed: Option<Symbol>,
om: &mut Module<'tcx>,
+ parent_id: Option<hir::HirId>,
) {
debug!("visiting item {:?}", item);
let name = renamed.unwrap_or(item.ident.name);
- let def_id = item.def_id.to_def_id();
+ let def_id = item.owner_id.to_def_id();
let is_pub = self.cx.tcx.visibility(def_id).is_public();
if is_pub {
- self.store_path(item.def_id.to_def_id());
+ self.store_path(item.owner_id.to_def_id());
}
match item.kind {
}
}
- om.items.push((item, renamed))
+ om.items.push((item, renamed, parent_id))
}
hir::ItemKind::Macro(ref macro_def, _) => {
// `#[macro_export] macro_rules!` items are handled separately in `visit()`,
// 3. We're inlining, since a reexport where inlining has been requested
// should be inlined even if it is also documented at the top level.
- let def_id = item.def_id.to_def_id();
+ let def_id = item.owner_id.to_def_id();
let is_macro_2_0 = !macro_def.macro_rules;
let nonexported = !self.cx.tcx.has_attr(def_id, sym::macro_export);
if is_macro_2_0 || nonexported || self.inlining {
- om.items.push((item, renamed));
+ om.items.push((item, renamed, None));
}
}
hir::ItemKind::Mod(ref m) => {
- om.mods.push(self.visit_mod_contents(item.hir_id(), m, name));
+ om.mods.push(self.visit_mod_contents(item.hir_id(), m, name, parent_id));
}
hir::ItemKind::Fn(..)
| hir::ItemKind::ExternCrate(..)
| hir::ItemKind::OpaqueTy(..)
| hir::ItemKind::Static(..)
| hir::ItemKind::Trait(..)
- | hir::ItemKind::TraitAlias(..) => om.items.push((item, renamed)),
+ | hir::ItemKind::TraitAlias(..) => om.items.push((item, renamed, parent_id)),
hir::ItemKind::Const(..) => {
// Underscore constants do not correspond to a nameable item and
// so are never useful in documentation.
if name != kw::Underscore {
- om.items.push((item, renamed));
+ om.items.push((item, renamed, parent_id));
}
}
hir::ItemKind::Impl(impl_) => {
// Don't duplicate impls when inlining or if it's implementing a trait, we'll pick
// them up regardless of where they're located.
if !self.inlining && impl_.of_trait.is_none() {
- om.items.push((item, None));
+ om.items.push((item, None, None));
}
}
}
om: &mut Module<'tcx>,
) {
// If inlining we only want to include public functions.
- if !self.inlining || self.cx.tcx.visibility(item.def_id).is_public() {
+ if !self.inlining || self.cx.tcx.visibility(item.owner_id).is_public() {
om.foreigns.push((item, renamed));
}
}
+use crate::core::DocContext;
use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::def::{DefKind, Res};
-use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_ID};
-use rustc_middle::middle::privacy::{AccessLevel, AccessLevels};
-use rustc_middle::ty::{TyCtxt, Visibility};
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::DefId;
+use rustc_middle::ty::TyCtxt;
// FIXME: this may not be exhaustive, but is sufficient for rustdocs current uses
-/// Similar to `librustc_privacy::EmbargoVisitor`, but also takes
-/// specific rustdoc annotations into account (i.e., `doc(hidden)`)
-pub(crate) struct LibEmbargoVisitor<'a, 'tcx> {
- tcx: TyCtxt<'tcx>,
- // Accessibility levels for reachable nodes
- access_levels: &'a mut AccessLevels<DefId>,
- // Previous accessibility level, None means unreachable
- prev_level: Option<AccessLevel>,
- // Keeps track of already visited modules, in case a module re-exports its parent
- visited_mods: FxHashSet<DefId>,
+#[derive(Default)]
+pub(crate) struct RustdocEffectiveVisibilities {
+ extern_public: FxHashSet<DefId>,
}
-impl<'a, 'tcx> LibEmbargoVisitor<'a, 'tcx> {
- pub(crate) fn new(cx: &'a mut crate::core::DocContext<'tcx>) -> LibEmbargoVisitor<'a, 'tcx> {
- LibEmbargoVisitor {
- tcx: cx.tcx,
- access_levels: &mut cx.cache.access_levels,
- prev_level: Some(AccessLevel::Public),
- visited_mods: FxHashSet::default(),
+macro_rules! define_method {
+ ($method:ident) => {
+ pub(crate) fn $method(&self, tcx: TyCtxt<'_>, def_id: DefId) -> bool {
+ match def_id.as_local() {
+ Some(def_id) => tcx.effective_visibilities(()).$method(def_id),
+ None => self.extern_public.contains(&def_id),
+ }
}
- }
-
- pub(crate) fn visit_lib(&mut self, cnum: CrateNum) {
- let did = cnum.as_def_id();
- self.update(did, Some(AccessLevel::Public));
- self.visit_mod(did);
- }
+ };
+}
- // Updates node level and returns the updated level
- fn update(&mut self, did: DefId, level: Option<AccessLevel>) -> Option<AccessLevel> {
- let is_hidden = self.tcx.is_doc_hidden(did);
+impl RustdocEffectiveVisibilities {
+ define_method!(is_directly_public);
+ define_method!(is_exported);
+ define_method!(is_reachable);
+}
- let old_level = self.access_levels.get_access_level(did);
- // Accessibility levels can only grow
- if level > old_level && !is_hidden {
- self.access_levels.set_access_level(
- did,
- || Visibility::Restricted(CRATE_DEF_ID),
- level.unwrap(),
- );
- level
- } else {
- old_level
- }
+pub(crate) fn lib_embargo_visit_item(cx: &mut DocContext<'_>, def_id: DefId) {
+ assert!(!def_id.is_local());
+ LibEmbargoVisitor {
+ tcx: cx.tcx,
+ extern_public: &mut cx.cache.effective_visibilities.extern_public,
+ visited_mods: Default::default(),
}
+ .visit_item(def_id)
+}
+
+/// Similar to `librustc_privacy::EmbargoVisitor`, but also takes
+/// specific rustdoc annotations into account (i.e., `doc(hidden)`)
+struct LibEmbargoVisitor<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
+ // Effective visibilities for reachable nodes
+ extern_public: &'a mut FxHashSet<DefId>,
+ // Keeps track of already visited modules, in case a module re-exports its parent
+ visited_mods: FxHashSet<DefId>,
+}
- pub(crate) fn visit_mod(&mut self, def_id: DefId) {
+impl LibEmbargoVisitor<'_, '_> {
+ fn visit_mod(&mut self, def_id: DefId) {
if !self.visited_mods.insert(def_id) {
return;
}
for item in self.tcx.module_children(def_id).iter() {
if let Some(def_id) = item.res.opt_def_id() {
- if self.tcx.def_key(def_id).parent.map_or(false, |d| d == def_id.index)
- || item.vis.is_public()
- {
- self.visit_item(item.res);
+ if item.vis.is_public() {
+ self.visit_item(def_id);
}
}
}
}
- fn visit_item(&mut self, res: Res<!>) {
- let def_id = res.def_id();
- let vis = self.tcx.visibility(def_id);
- let inherited_item_level = if vis.is_public() { self.prev_level } else { None };
-
- let item_level = self.update(def_id, inherited_item_level);
-
- if let Res::Def(DefKind::Mod, _) = res {
- let orig_level = self.prev_level;
-
- self.prev_level = item_level;
- self.visit_mod(def_id);
- self.prev_level = orig_level;
+ fn visit_item(&mut self, def_id: DefId) {
+ if !self.tcx.is_doc_hidden(def_id) {
+ self.extern_public.insert(def_id);
+ if self.tcx.def_kind(def_id) == DefKind::Mod {
+ self.visit_mod(def_id);
+ }
}
}
}
-Subproject commit 4b85255772114ca4946d95fe591933dae7d61991
+Subproject commit 2a2ea6b49e79325e0d10d33fac2b10ea3bebcc7c
pub crate_id: u32,
/// The list of path components for the fully qualified path of this item (e.g.
/// `["std", "io", "lazy", "Lazy"]` for `std::io::lazy::Lazy`).
+ ///
+ /// Note that items can appear in multiple paths, and the one chosen is implementation
+ /// defined. Currenty, this is the full path to where the item was defined. Eg
+ /// [`String`] is currently `["alloc", "string", "String"]` and [`HashMap`] is
+ /// `["std", "collections", "hash", "map", "HashMap"]`, but this is subject to change.
pub path: Vec<String>,
/// Whether this item is a struct, trait, macro, etc.
pub kind: ItemKind,
--- /dev/null
+// assembly-output: emit-asm
+// compile-flags: -Copt-level=1
+// only-x86_64
+// min-llvm-version: 15.0
+#![crate_type = "rlib"]
+
+// CHECK-LABEL: old_style
+// CHECK: movq %{{.*}}, %rax
+// CHECK: orq $1, %rax
+// CHECK: retq
+#[no_mangle]
+pub fn old_style(a: *mut u8) -> *mut u8 {
+ (a as usize | 1) as *mut u8
+}
+
+// CHECK-LABEL: cheri_compat
+// CHECK: movq %{{.*}}, %rax
+// CHECK: orq $1, %rax
+// CHECK: retq
+#[no_mangle]
+pub fn cheri_compat(a: *mut u8) -> *mut u8 {
+ let old = a as usize;
+ let new = old | 1;
+ let diff = new.wrapping_sub(old);
+ a.wrapping_add(diff)
+}
+
+// CHECK-LABEL: definitely_not_a_null_pointer
+// CHECK: movq %{{.*}}, %rax
+// CHECK: orq $1, %rax
+// CHECK: retq
+#[no_mangle]
+pub fn definitely_not_a_null_pointer(a: *mut u8) -> *mut u8 {
+ let old = a as usize;
+ let new = old | 1;
+ a.wrapping_sub(old).wrapping_add(new)
+}
--- /dev/null
+use std::sync::atomic::{AtomicPtr, Ordering};
+
+#[inline(always)]
+pub fn memrchr() {
+ fn detect() {}
+
+ static CROSS_CRATE_STATIC_ITEM: AtomicPtr<()> = AtomicPtr::new(detect as *mut ());
+
+ unsafe {
+ let fun = CROSS_CRATE_STATIC_ITEM.load(Ordering::SeqCst);
+ std::mem::transmute::<*mut (), fn()>(fun)()
+ }
+}
pub trait Copy { }
#[lang = "receiver"]
pub trait Receiver { }
+#[lang = "tuple_trait"]
+pub trait Tuple { }
pub struct Result<T, E> { _a: T, _b: E }
pub unsafe fn drop_in_place<T: ?Sized>(_: *mut T) {}
#[lang = "fn_once"]
-pub trait FnOnce<Args> {
+pub trait FnOnce<Args: Tuple> {
#[lang = "fn_once_output"]
type Output;
}
#[lang = "fn_mut"]
-pub trait FnMut<Args> : FnOnce<Args> {
+pub trait FnMut<Args: Tuple> : FnOnce<Args> {
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}
#[lang = "fn"]
-pub trait Fn<Args>: FnOnce<Args> {
+pub trait Fn<Args: Tuple>: FnOnce<Args> {
/// Performs the call operation.
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
}
-impl<'a, A, R> FnOnce<A> for &'a fn(A) -> R {
- type Output = R;
-
- extern "rust-call" fn call_once(self, args: A) -> R {
- (*self)(args)
- }
-}
-
pub static mut STORAGE_FOO: fn(&usize, &mut u32) -> Result<(), ()> = arbitrary_black_box;
pub static mut STORAGE_BAR: u32 = 12;
// CHECK-LABEL: @lookup_inc
#[no_mangle]
pub fn lookup_inc(buf: &[u8; 5], f: Bar) -> u8 {
- // FIXME: panic check can be removed by adding the assumes back after https://github.com/rust-lang/rust/pull/98332
- // CHECK: panic_bounds_check
+ // CHECK-NOT: panic_bounds_check
buf[f as usize + 1]
}
// CHECK-LABEL: @lookup_dec
#[no_mangle]
pub fn lookup_dec(buf: &[u8; 5], f: Bar) -> u8 {
- // FIXME: panic check can be removed by adding the assumes back after https://github.com/rust-lang/rust/pull/98332
- // CHECK: panic_bounds_check
+ // CHECK-NOT: panic_bounds_check
buf[f as usize - 1]
}
// CHECK-LABEL: @access
#[no_mangle]
pub fn access(array: &[usize; 12], exc: Exception) -> usize {
- // FIXME: panic check can be removed by adding the assumes back after https://github.com/rust-lang/rust/pull/98332
- // CHECK: panic_bounds_check
+ // CHECK-NOT: panic_bounds_check
array[(exc as u8 - 4) as usize]
}
// CHECK-LABEL: @lookup_unmodified
#[no_mangle]
pub fn lookup_unmodified(buf: &[u8; 5], f: Bar) -> u8 {
- // FIXME: panic check can be removed by adding the assumes back after https://github.com/rust-lang/rust/pull/98332
- // CHECK: panic_bounds_check
+ // CHECK-NOT: panic_bounds_check
buf[f as usize]
}
extern "C" {
// CHECK-LABEL: declare{{.*}}void @foo()
// CHECK-SAME: [[ATTRS:#[0-9]+]]
- // CHECK-DAG: attributes [[ATTRS]] = { {{.*}}readnone{{.*}} }
+ // The attribute changed from `readnone` to `memory(none)` with LLVM 16.0.
+ // CHECK-DAG: attributes [[ATTRS]] = { {{.*}}{{readnone|memory\(none\)}}{{.*}} }
#[ffi_const] pub fn foo();
}
extern "C" {
// CHECK-LABEL: declare{{.*}}void @foo()
// CHECK-SAME: [[ATTRS:#[0-9]+]]
- // CHECK-DAG: attributes [[ATTRS]] = { {{.*}}readonly{{.*}} }
+ // The attribute changed from `readonly` to `memory(read)` with LLVM 16.0.
+ // CHECK-DAG: attributes [[ATTRS]] = { {{.*}}{{readonly|memory\(read\)}}{{.*}} }
#[ffi_pure] pub fn foo();
}
--- /dev/null
+// compile-flags: -O -C debug-assertions=yes
+
+#![crate_type = "lib"]
+#![feature(strict_provenance)]
+
+#[no_mangle]
+pub fn test(src: *const u8, dst: *const u8) -> usize {
+ // CHECK-LABEL: @test(
+ // CHECK-NOT: panic
+ let src_usize = src.addr();
+ let dst_usize = dst.addr();
+ if src_usize > dst_usize {
+ return src_usize - dst_usize;
+ }
+ return 0;
+}
--- /dev/null
+// compile-flags: -O -C lto=thin -C prefer-dynamic=no
+// only-windows
+// aux-build:static_dllimport_aux.rs
+
+// Test that on Windows, when performing ThinLTO, we do not mark cross-crate static items with
+// dllimport because lld does not fix the symbol names for us.
+
+extern crate static_dllimport_aux;
+
+// CHECK-LABEL: @{{.+}}CROSS_CRATE_STATIC_ITEM{{.+}} =
+// CHECK-SAME: external local_unnamed_addr global %"{{.+}}AtomicPtr
+
+pub fn main() {
+ static_dllimport_aux::memrchr();
+}
--- /dev/null
+// compile-flags: -C no-prepopulate-passes -O
+
+#![crate_type = "lib"]
+
+pub enum E {
+ A,
+ B,
+ C,
+}
+
+// CHECK-LABEL: @exhaustive_match
+#[no_mangle]
+pub fn exhaustive_match(e: E) -> u8 {
+// CHECK: switch{{.*}}, label %[[OTHERWISE:[a-zA-Z0-9_]+]] [
+// CHECK-NEXT: i[[TY:[0-9]+]] [[DISCR:[0-9]+]], label %[[A:[a-zA-Z0-9_]+]]
+// CHECK-NEXT: i[[TY:[0-9]+]] [[DISCR:[0-9]+]], label %[[B:[a-zA-Z0-9_]+]]
+// CHECK-NEXT: i[[TY:[0-9]+]] [[DISCR:[0-9]+]], label %[[C:[a-zA-Z0-9_]+]]
+// CHECK-NEXT: ]
+// CHECK: [[OTHERWISE]]:
+// CHECK-NEXT: unreachable
+//
+// CHECK: [[A]]:
+// CHECK-NEXT: store i8 0, {{i8\*|ptr}} %1, align 1
+// CHECK-NEXT: br label %[[EXIT:[a-zA-Z0-9_]+]]
+// CHECK: [[B]]:
+// CHECK-NEXT: store i8 1, {{i8\*|ptr}} %1, align 1
+// CHECK-NEXT: br label %[[EXIT]]
+// CHECK: [[C]]:
+// CHECK-NEXT: store i8 2, {{i8\*|ptr}} %1, align 1
+// CHECK-NEXT: br label %[[EXIT]]
+ match e {
+ E::A => 0,
+ E::B => 1,
+ E::C => 2,
+ }
+}
+
+#[repr(u16)]
+pub enum E2 {
+ A = 13,
+ B = 42,
+}
+
+// For optimized code we produce a switch with an unreachable target as the `otherwise` so LLVM
+// knows the possible values. Compare with `src/test/codegen/match-unoptimized.rs`.
+
+// CHECK-LABEL: @exhaustive_match_2
+#[no_mangle]
+pub fn exhaustive_match_2(e: E2) -> u8 {
+ // CHECK: switch i16 %{{.+}}, label %[[UNREACH:.+]] [
+ // CHECK-NEXT: i16 13,
+ // CHECK-NEXT: i16 42,
+ // CHECK-NEXT: ]
+ // CHECK: [[UNREACH]]:
+ // CHECK-NEXT: unreachable
+ match e {
+ E2::A => 0,
+ E2::B => 1,
+ }
+}
--- /dev/null
+// compile-flags: -C no-prepopulate-passes -Copt-level=0
+
+#![crate_type = "lib"]
+
+#[repr(u16)]
+pub enum E2 {
+ A = 13,
+ B = 42,
+}
+
+// For unoptimized code we produce a `br` instead of a `switch`. Compare with
+// `src/test/codegen/match-optimized.rs`
+
+// CHECK-LABEL: @exhaustive_match_2
+#[no_mangle]
+pub fn exhaustive_match_2(e: E2) -> u8 {
+ // CHECK: %[[CMP:.+]] = icmp eq i16 %{{.+}}, 13
+ // CHECK-NEXT: br i1 %[[CMP:.+]],
+ match e {
+ E2::A => 0,
+ E2::B => 1,
+ }
+}
+++ /dev/null
-// compile-flags: -C no-prepopulate-passes
-
-#![crate_type = "lib"]
-
-pub enum E {
- A,
- B,
-}
-
-// CHECK-LABEL: @exhaustive_match
-#[no_mangle]
-pub fn exhaustive_match(e: E) -> u8 {
-// CHECK: switch{{.*}}, label %[[OTHERWISE:[a-zA-Z0-9_]+]] [
-// CHECK-NEXT: i[[TY:[0-9]+]] [[DISCR:[0-9]+]], label %[[A:[a-zA-Z0-9_]+]]
-// CHECK-NEXT: i[[TY:[0-9]+]] [[DISCR:[0-9]+]], label %[[B:[a-zA-Z0-9_]+]]
-// CHECK-NEXT: ]
-// CHECK: [[OTHERWISE]]:
-// CHECK-NEXT: unreachable
-// CHECK: [[A]]:
-// CHECK-NEXT: store i8 0, {{i8\*|ptr}} %1, align 1
-// CHECK-NEXT: br label %[[EXIT:[a-zA-Z0-9_]+]]
-// CHECK: [[B]]:
-// CHECK-NEXT: store i8 1, {{i8\*|ptr}} %1, align 1
-// CHECK-NEXT: br label %[[EXIT:[a-zA-Z0-9_]+]]
- match e {
- E::A => 0,
- E::B => 1,
- }
-}
--- /dev/null
+// compile-flags: -O -g
+
+#![crate_type = "lib"]
+
+#[inline(always)]
+fn foo() {
+ bar();
+}
+
+#[inline(never)]
+#[no_mangle]
+fn bar() {
+ panic!();
+}
+
+#[no_mangle]
+pub fn example() {
+ foo();
+}
+
+// CHECK-LABEL: @example
+// CHECK: tail call void @bar(), !dbg [[DBG_ID:![0-9]+]]
+// CHECK: [[DBG_ID]] = !DILocation(line: 7,
+// CHECK-SAME: inlinedAt: [[INLINE_ID:![0-9]+]])
+// CHECK: [[INLINE_ID]] = !DILocation(line: 18,
// gdbg-check:$15 = {data_ptr = [...] "Hello, World!", length = 13}
// gdbr-check:$15 = "Hello, World!"
-
// === LLDB TESTS ==================================================================================
// lldb-command:run
// lldbg-check:[...]$12 = 3.5
// lldbr-check:(f64) f64 = 3.5
-
// === CDB TESTS ===================================================================================
// cdb-command:g
// cdb-command:.enable_unicode 1
// FIXME(#88840): The latest version of the Windows SDK broke the visualizer for str.
// cdb-command:dx s
-// cdb-check:s : [...] [Type: str]
+// cdb-check:s : [...] [Type: ref$<str$>]
#![allow(unused_variables)]
#![feature(omit_gdb_pretty_printer_section)]
_zzz(); // #break
}
-fn _zzz() {()}
+fn _zzz() {
+ ()
+}
// cdb-check: niche_w_fields_3_niche5,d : F [Type: enum2$<msvc_pretty_enums::NicheLayoutWithFields3>]
// cdb-command: dx -r3 niche_w_fields_std_result_ok,d
-// cdb-check: niche_w_fields_std_result_ok,d : Ok [Type: enum2$<core::result::Result<alloc::boxed::Box<slice$<u8>,alloc::alloc::Global>,u64> >]
-// cdb-check: [+0x[...]] __0 [Type: alloc::boxed::Box<slice$<u8>,alloc::alloc::Global>]
+// cdb-check: niche_w_fields_std_result_ok,d : Ok [Type: enum2$<core::result::Result<alloc::boxed::Box<slice2$<u8>,alloc::alloc::Global>,u64> >]
+// cdb-check: [+0x[...]] __0 [Type: alloc::boxed::Box<slice2$<u8>,alloc::alloc::Global>]
// cdb-check: [+0x[...]] data_ptr : [...]
// cdb-check: [+0x[...]] length : 3 [...]
// cdb-command: dx -r3 niche_w_fields_std_result_err,d
-// cdb-check: niche_w_fields_std_result_err,d : Err [Type: enum2$<core::result::Result<alloc::boxed::Box<slice$<u8>,alloc::alloc::Global>,u64> >]
+// cdb-check: niche_w_fields_std_result_err,d : Err [Type: enum2$<core::result::Result<alloc::boxed::Box<slice2$<u8>,alloc::alloc::Global>,u64> >]
// cdb-check: [+0x[...]] __0 : 789 [Type: unsigned __int64]
// cdb-command: dx -r2 arbitrary_discr1,d
// cdb-command: g
// cdb-command: dx s
-// cdb-check:s : "this is a static str" [Type: str]
+// cdb-check:s : "this is a static str" [Type: ref$<str$>]
// cdb-check: [len] : 0x14 [Type: unsigned [...]]
// cdb-check: [chars]
// cdb-command: g
// cdb-command: dx s
-// cdb-check:s : { len=0x5 } [Type: slice$<u8>]
+// cdb-check:s : { len=0x5 } [Type: ref$<slice2$<u8> >]
// cdb-check: [len] : 0x5 [Type: unsigned [...]]
// cdb-check: [0] : 0x1 [Type: unsigned char]
// cdb-check: [1] : 0x2 [Type: unsigned char]
// cdb-command: g
// cdb-command: dx slice,d
-// cdb-check:slice,d : { len=4 } [Type: slice$<i32>]
+// cdb-check:slice,d : { len=4 } [Type: ref$<slice2$<i32> >]
// cdb-check: [len] : 4 [Type: [...]]
// cdb-check: [0] : 0 [Type: int]
// cdb-check: [1] : 1 [Type: int]
// cdb-check: [3] : 7 [Type: unsigned __int64]
// cdb-command: dx str_slice
-// cdb-check:str_slice : "IAMA string slice!" [Type: str]
+// cdb-check:str_slice : "IAMA string slice!" [Type: ref$<str$>]
// cdb-command: dx string
// cdb-check:string : "IAMA string!" [Type: [...]::String]
// cdb-check: [Weak reference count] : 2 [Type: core::cell::Cell<usize>]
// cdb-command:dx slice_rc,d
-// cdb-check:slice_rc,d : { len=3 } [Type: alloc::rc::Rc<slice$<u32> >]
+// cdb-check:slice_rc,d : { len=3 } [Type: alloc::rc::Rc<slice2$<u32> >]
// cdb-check: [Length] : 3 [Type: [...]]
// cdb-check: [Reference count] : 41 [Type: core::cell::Cell<usize>]
// cdb-check: [Weak reference count] : 2 [Type: core::cell::Cell<usize>]
// cdb-check: [2] : 3 [Type: u32]
// cdb-command:dx slice_rc_weak,d
-// cdb-check:slice_rc_weak,d : { len=3 } [Type: alloc::rc::Weak<slice$<u32> >]
+// cdb-check:slice_rc_weak,d : { len=3 } [Type: alloc::rc::Weak<slice2$<u32> >]
// cdb-check: [Length] : 3 [Type: [...]]
// cdb-check: [Reference count] : 41 [Type: core::cell::Cell<usize>]
// cdb-check: [Weak reference count] : 2 [Type: core::cell::Cell<usize>]
// cdb-check: [Weak reference count] : 2 [Type: core::sync::atomic::AtomicUsize]
// cdb-command:dx slice_arc,d
-// cdb-check:slice_arc,d : { len=3 } [Type: alloc::sync::Arc<slice$<u32> >]
+// cdb-check:slice_arc,d : { len=3 } [Type: alloc::sync::Arc<slice2$<u32> >]
// cdb-check: [Length] : 3 [Type: [...]]
// cdb-check: [Reference count] : 61 [Type: core::sync::atomic::AtomicUsize]
// cdb-check: [Weak reference count] : 2 [Type: core::sync::atomic::AtomicUsize]
// cdb-check: [2] : 6 [Type: u32]
// cdb-command:dx slice_arc_weak,d
-// cdb-check:slice_arc_weak,d : { len=3 } [Type: alloc::sync::Weak<slice$<u32> >]
+// cdb-check:slice_arc_weak,d : { len=3 } [Type: alloc::sync::Weak<slice2$<u32> >]
// cdb-check: [Length] : 3 [Type: [...]]
// cdb-check: [Reference count] : 61 [Type: core::sync::atomic::AtomicUsize]
// cdb-check: [Weak reference count] : 2 [Type: core::sync::atomic::AtomicUsize]
// cdb-command: g
// cdb-command: dx x,d
-// cdb-check:x,d : Ok [Type: enum2$<core::result::Result<i32,str> >]
+// cdb-check:x,d : Ok [Type: enum2$<core::result::Result<i32,ref$<str$> > >]
// cdb-check: [...] __0 : -3 [Type: int]
// cdb-command: dx y
-// cdb-check:y : Err [Type: enum2$<core::result::Result<i32,str> >]
-// cdb-check: [...] __0 : "Some error message" [Type: str]
+// cdb-check:y : Err [Type: enum2$<core::result::Result<i32,ref$<str$> > >]
+// cdb-check: [...] __0 : "Some error message" [Type: ref$<str$>]
fn main() {
let x: Result<i32, &str> = Ok(-3);
// gdb-check:type = &[usize]
// gdb-command:whatis slice2
-// gdb-check:type = &[type_names::mod1::Enum2]
+// gdb-check:type = &mut [type_names::mod1::Enum2]
// TRAITS
// gdb-command:whatis box_trait
// cdb-check:struct alloc::vec::Vec<usize,alloc::alloc::Global> vec1 = [...]
// cdb-check:struct alloc::vec::Vec<enum2$<type_names::mod1::Enum2>,alloc::alloc::Global> vec2 = [...]
// cdb-command:dv /t slice*
-// cdb-check:struct slice$<usize> slice1 = [...]
-// cdb-check:struct slice$<enum2$<type_names::mod1::Enum2> > slice2 = [...]
+// cdb-check:struct ref$<slice2$<usize> > slice1 = [...]
+// cdb-check:struct ref_mut$<slice2$<enum2$<type_names::mod1::Enum2> > > slice2 = [...]
// TRAITS
// cdb-command:dv /t *_trait
let vec1 = vec![0_usize, 2, 3];
let slice1 = &*vec1;
- let vec2 = vec![mod1::Enum2::Variant2(Struct1)];
- let slice2 = &*vec2;
+ let mut vec2 = vec![mod1::Enum2::Variant2(Struct1)];
+ let slice2 = &mut *vec2;
// Trait Objects
let box_trait = Box::new(0_isize) as Box<dyn Trait1>;
// cdb-command: g
// cdb-command:dx a
-// cdb-check:a [Type: ref$<unsized::Foo<slice$<u8> > >]
-// cdb-check: [+0x000] data_ptr : 0x[...] [Type: unsized::Foo<slice$<u8> > *]
+// cdb-check:a [Type: ref$<unsized::Foo<slice2$<u8> > >]
+// cdb-check: [+0x000] data_ptr : 0x[...] [Type: unsized::Foo<slice2$<u8> > *]
// cdb-check: [...] length : 0x4 [Type: unsigned [...]int[...]
// cdb-command:dx b
-// cdb-check:b [Type: ref$<unsized::Foo<unsized::Foo<slice$<u8> > > >]
-// cdb-check: [+0x000] data_ptr : 0x[...] [Type: unsized::Foo<unsized::Foo<slice$<u8> > > *]
+// cdb-check:b [Type: ref$<unsized::Foo<unsized::Foo<slice2$<u8> > > >]
+// cdb-check: [+0x000] data_ptr : 0x[...] [Type: unsized::Foo<unsized::Foo<slice2$<u8> > > *]
// cdb-check: [...] length : 0x4 [Type: unsigned [...]int[...]
// cdb-command:dx c
// cdb-check:[...] vtable : 0x[...] [Type: unsigned [...]int[...] (*)[3]]
// cdb-command:dx tuple_slice
-// cdb-check:tuple_slice [Type: ref$<tuple$<i32,i32,slice$<i32> > >]
-// cdb-check: [+0x000] data_ptr : 0x[...] [Type: tuple$<i32,i32,slice$<i32> > *]
+// cdb-check:tuple_slice [Type: ref$<tuple$<i32,i32,slice2$<i32> > >]
+// cdb-check: [+0x000] data_ptr : 0x[...] [Type: tuple$<i32,i32,slice2$<i32> > *]
// cdb-check: [...] length : 0x2 [Type: unsigned [...]int[...]
// cdb-command:dx tuple_dyn
// Change calling convention ---------------------------------------------------
#[cfg(any(cfail1,cfail4))]
extern "C" {
- pub fn change_calling_convention(c: i32);
+ pub fn change_calling_convention(c: (i32,));
}
#[cfg(not(any(cfail1,cfail4)))]
#[rustc_clean(cfg = "cfail5", except = "hir_owner,hir_owner_nodes")]
#[rustc_clean(cfg = "cfail6")]
extern "rust-call" {
- pub fn change_calling_convention(c: i32);
+ pub fn change_calling_convention(c: (i32,));
}
// Make function public --------------------------------------------------------
+++ /dev/null
-// EMIT_MIR address_of.address_of_reborrow.SimplifyCfg-initial.after.mir
-
-fn address_of_reborrow() {
- let y = &[0; 10];
- let mut z = &mut [0; 10];
-
- y as *const _;
- y as *const [i32; 10];
- y as *const dyn Send;
- y as *const [i32];
- y as *const i32; // This is a cast, not a coercion
-
- let p: *const _ = y;
- let p: *const [i32; 10] = y;
- let p: *const dyn Send = y;
- let p: *const [i32] = y;
-
- z as *const _;
- z as *const [i32; 10];
- z as *const dyn Send;
- z as *const [i32];
-
- let p: *const _ = z;
- let p: *const [i32; 10] = z;
- let p: *const dyn Send = z;
- let p: *const [i32] = z;
-
- z as *mut _;
- z as *mut [i32; 10];
- z as *mut dyn Send;
- z as *mut [i32];
-
- let p: *mut _ = z;
- let p: *mut [i32; 10] = z;
- let p: *mut dyn Send = z;
- let p: *mut [i32] = z;
-}
-
-// The normal borrows here should be preserved
-// EMIT_MIR address_of.borrow_and_cast.SimplifyCfg-initial.after.mir
-fn borrow_and_cast(mut x: i32) {
- let p = &x as *const i32;
- let q = &mut x as *const i32;
- let r = &mut x as *mut i32;
-}
-
-fn main() {}
// MIR for `address_of_reborrow` after SimplifyCfg-initial
| User Type Annotations
-| 0: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) }, span: $DIR/address-of.rs:7:5: 7:18, inferred_ty: *const [i32; 10]
-| 1: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*const dyn std::marker::Send) }, span: $DIR/address-of.rs:9:5: 9:25, inferred_ty: *const dyn std::marker::Send
-| 2: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) }, span: $DIR/address-of.rs:13:12: 13:20, inferred_ty: *const [i32; 10]
-| 3: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) }, span: $DIR/address-of.rs:13:12: 13:20, inferred_ty: *const [i32; 10]
-| 4: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32; 10]) }, span: $DIR/address-of.rs:14:12: 14:28, inferred_ty: *const [i32; 10]
-| 5: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32; 10]) }, span: $DIR/address-of.rs:14:12: 14:28, inferred_ty: *const [i32; 10]
-| 6: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*const dyn std::marker::Send) }, span: $DIR/address-of.rs:15:12: 15:27, inferred_ty: *const dyn std::marker::Send
-| 7: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*const dyn std::marker::Send) }, span: $DIR/address-of.rs:15:12: 15:27, inferred_ty: *const dyn std::marker::Send
-| 8: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) }, span: $DIR/address-of.rs:16:12: 16:24, inferred_ty: *const [i32]
-| 9: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) }, span: $DIR/address-of.rs:16:12: 16:24, inferred_ty: *const [i32]
-| 10: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) }, span: $DIR/address-of.rs:18:5: 18:18, inferred_ty: *const [i32; 10]
-| 11: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*const dyn std::marker::Send) }, span: $DIR/address-of.rs:20:5: 20:25, inferred_ty: *const dyn std::marker::Send
-| 12: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) }, span: $DIR/address-of.rs:23:12: 23:20, inferred_ty: *const [i32; 10]
-| 13: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) }, span: $DIR/address-of.rs:23:12: 23:20, inferred_ty: *const [i32; 10]
-| 14: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32; 10]) }, span: $DIR/address-of.rs:24:12: 24:28, inferred_ty: *const [i32; 10]
-| 15: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32; 10]) }, span: $DIR/address-of.rs:24:12: 24:28, inferred_ty: *const [i32; 10]
-| 16: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*const dyn std::marker::Send) }, span: $DIR/address-of.rs:25:12: 25:27, inferred_ty: *const dyn std::marker::Send
-| 17: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*const dyn std::marker::Send) }, span: $DIR/address-of.rs:25:12: 25:27, inferred_ty: *const dyn std::marker::Send
-| 18: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) }, span: $DIR/address-of.rs:26:12: 26:24, inferred_ty: *const [i32]
-| 19: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) }, span: $DIR/address-of.rs:26:12: 26:24, inferred_ty: *const [i32]
-| 20: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) }, span: $DIR/address-of.rs:28:5: 28:16, inferred_ty: *mut [i32; 10]
-| 21: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*mut dyn std::marker::Send) }, span: $DIR/address-of.rs:30:5: 30:23, inferred_ty: *mut dyn std::marker::Send
-| 22: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) }, span: $DIR/address-of.rs:33:12: 33:18, inferred_ty: *mut [i32; 10]
-| 23: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) }, span: $DIR/address-of.rs:33:12: 33:18, inferred_ty: *mut [i32; 10]
-| 24: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*mut [i32; 10]) }, span: $DIR/address-of.rs:34:12: 34:26, inferred_ty: *mut [i32; 10]
-| 25: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*mut [i32; 10]) }, span: $DIR/address-of.rs:34:12: 34:26, inferred_ty: *mut [i32; 10]
-| 26: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*mut dyn std::marker::Send) }, span: $DIR/address-of.rs:35:12: 35:25, inferred_ty: *mut dyn std::marker::Send
-| 27: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*mut dyn std::marker::Send) }, span: $DIR/address-of.rs:35:12: 35:25, inferred_ty: *mut dyn std::marker::Send
-| 28: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*mut [i32]) }, span: $DIR/address-of.rs:36:12: 36:22, inferred_ty: *mut [i32]
-| 29: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*mut [i32]) }, span: $DIR/address-of.rs:36:12: 36:22, inferred_ty: *mut [i32]
+| 0: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) }, span: $DIR/address_of.rs:7:5: 7:18, inferred_ty: *const [i32; 10]
+| 1: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*const dyn std::marker::Send) }, span: $DIR/address_of.rs:9:5: 9:25, inferred_ty: *const dyn std::marker::Send
+| 2: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) }, span: $DIR/address_of.rs:13:12: 13:20, inferred_ty: *const [i32; 10]
+| 3: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) }, span: $DIR/address_of.rs:13:12: 13:20, inferred_ty: *const [i32; 10]
+| 4: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32; 10]) }, span: $DIR/address_of.rs:14:12: 14:28, inferred_ty: *const [i32; 10]
+| 5: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32; 10]) }, span: $DIR/address_of.rs:14:12: 14:28, inferred_ty: *const [i32; 10]
+| 6: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*const dyn std::marker::Send) }, span: $DIR/address_of.rs:15:12: 15:27, inferred_ty: *const dyn std::marker::Send
+| 7: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*const dyn std::marker::Send) }, span: $DIR/address_of.rs:15:12: 15:27, inferred_ty: *const dyn std::marker::Send
+| 8: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) }, span: $DIR/address_of.rs:16:12: 16:24, inferred_ty: *const [i32]
+| 9: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) }, span: $DIR/address_of.rs:16:12: 16:24, inferred_ty: *const [i32]
+| 10: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) }, span: $DIR/address_of.rs:18:5: 18:18, inferred_ty: *const [i32; 10]
+| 11: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*const dyn std::marker::Send) }, span: $DIR/address_of.rs:20:5: 20:25, inferred_ty: *const dyn std::marker::Send
+| 12: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) }, span: $DIR/address_of.rs:23:12: 23:20, inferred_ty: *const [i32; 10]
+| 13: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*const ^0) }, span: $DIR/address_of.rs:23:12: 23:20, inferred_ty: *const [i32; 10]
+| 14: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32; 10]) }, span: $DIR/address_of.rs:24:12: 24:28, inferred_ty: *const [i32; 10]
+| 15: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32; 10]) }, span: $DIR/address_of.rs:24:12: 24:28, inferred_ty: *const [i32; 10]
+| 16: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*const dyn std::marker::Send) }, span: $DIR/address_of.rs:25:12: 25:27, inferred_ty: *const dyn std::marker::Send
+| 17: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*const dyn std::marker::Send) }, span: $DIR/address_of.rs:25:12: 25:27, inferred_ty: *const dyn std::marker::Send
+| 18: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) }, span: $DIR/address_of.rs:26:12: 26:24, inferred_ty: *const [i32]
+| 19: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*const [i32]) }, span: $DIR/address_of.rs:26:12: 26:24, inferred_ty: *const [i32]
+| 20: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) }, span: $DIR/address_of.rs:28:5: 28:16, inferred_ty: *mut [i32; 10]
+| 21: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*mut dyn std::marker::Send) }, span: $DIR/address_of.rs:30:5: 30:23, inferred_ty: *mut dyn std::marker::Send
+| 22: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) }, span: $DIR/address_of.rs:33:12: 33:18, inferred_ty: *mut [i32; 10]
+| 23: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Ty(General(U0)) }], value: Ty(*mut ^0) }, span: $DIR/address_of.rs:33:12: 33:18, inferred_ty: *mut [i32; 10]
+| 24: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*mut [i32; 10]) }, span: $DIR/address_of.rs:34:12: 34:26, inferred_ty: *mut [i32; 10]
+| 25: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*mut [i32; 10]) }, span: $DIR/address_of.rs:34:12: 34:26, inferred_ty: *mut [i32; 10]
+| 26: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*mut dyn std::marker::Send) }, span: $DIR/address_of.rs:35:12: 35:25, inferred_ty: *mut dyn std::marker::Send
+| 27: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }], value: Ty(*mut dyn std::marker::Send) }, span: $DIR/address_of.rs:35:12: 35:25, inferred_ty: *mut dyn std::marker::Send
+| 28: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*mut [i32]) }, span: $DIR/address_of.rs:36:12: 36:22, inferred_ty: *mut [i32]
+| 29: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*mut [i32]) }, span: $DIR/address_of.rs:36:12: 36:22, inferred_ty: *mut [i32]
|
fn address_of_reborrow() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/address-of.rs:+0:26: +0:26
- let _1: &[i32; 10]; // in scope 0 at $DIR/address-of.rs:+1:9: +1:10
- let _2: [i32; 10]; // in scope 0 at $DIR/address-of.rs:+1:14: +1:21
- let mut _4: [i32; 10]; // in scope 0 at $DIR/address-of.rs:+2:22: +2:29
- let _5: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+4:5: +4:18
- let mut _6: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+4:5: +4:18
- let _7: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+5:5: +5:26
- let _8: *const dyn std::marker::Send; // in scope 0 at $DIR/address-of.rs:+6:5: +6:25
- let mut _9: *const dyn std::marker::Send; // in scope 0 at $DIR/address-of.rs:+6:5: +6:25
- let mut _10: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+6:5: +6:6
- let _11: *const [i32]; // in scope 0 at $DIR/address-of.rs:+7:5: +7:22
- let mut _12: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+7:5: +7:6
- let _13: *const i32; // in scope 0 at $DIR/address-of.rs:+8:5: +8:20
- let mut _14: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+8:5: +8:6
- let mut _18: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+12:30: +12:31
- let mut _20: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+13:27: +13:28
- let _21: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+15:5: +15:18
- let mut _22: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+15:5: +15:18
- let _23: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+16:5: +16:26
- let _24: *const dyn std::marker::Send; // in scope 0 at $DIR/address-of.rs:+17:5: +17:25
- let mut _25: *const dyn std::marker::Send; // in scope 0 at $DIR/address-of.rs:+17:5: +17:25
- let mut _26: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+17:5: +17:6
- let _27: *const [i32]; // in scope 0 at $DIR/address-of.rs:+18:5: +18:22
- let mut _28: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+18:5: +18:6
- let mut _32: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+22:30: +22:31
- let mut _34: *const [i32; 10]; // in scope 0 at $DIR/address-of.rs:+23:27: +23:28
- let _35: *mut [i32; 10]; // in scope 0 at $DIR/address-of.rs:+25:5: +25:16
- let mut _36: *mut [i32; 10]; // in scope 0 at $DIR/address-of.rs:+25:5: +25:16
- let _37: *mut [i32; 10]; // in scope 0 at $DIR/address-of.rs:+26:5: +26:24
- let _38: *mut dyn std::marker::Send; // in scope 0 at $DIR/address-of.rs:+27:5: +27:23
- let mut _39: *mut dyn std::marker::Send; // in scope 0 at $DIR/address-of.rs:+27:5: +27:23
- let mut _40: *mut [i32; 10]; // in scope 0 at $DIR/address-of.rs:+27:5: +27:6
- let _41: *mut [i32]; // in scope 0 at $DIR/address-of.rs:+28:5: +28:20
- let mut _42: *mut [i32; 10]; // in scope 0 at $DIR/address-of.rs:+28:5: +28:6
- let mut _46: *mut [i32; 10]; // in scope 0 at $DIR/address-of.rs:+32:28: +32:29
- let mut _48: *mut [i32; 10]; // in scope 0 at $DIR/address-of.rs:+33:25: +33:26
+ let mut _0: (); // return place in scope 0 at $DIR/address_of.rs:+0:26: +0:26
+ let _1: &[i32; 10]; // in scope 0 at $DIR/address_of.rs:+1:9: +1:10
+ let _2: [i32; 10]; // in scope 0 at $DIR/address_of.rs:+1:14: +1:21
+ let mut _4: [i32; 10]; // in scope 0 at $DIR/address_of.rs:+2:22: +2:29
+ let _5: *const [i32; 10]; // in scope 0 at $DIR/address_of.rs:+4:5: +4:18
+ let mut _6: *const [i32; 10]; // in scope 0 at $DIR/address_of.rs:+4:5: +4:18
+ let _7: *const [i32; 10]; // in scope 0 at $DIR/address_of.rs:+5:5: +5:26
+ let _8: *const dyn std::marker::Send; // in scope 0 at $DIR/address_of.rs:+6:5: +6:25
+ let mut _9: *const dyn std::marker::Send; // in scope 0 at $DIR/address_of.rs:+6:5: +6:25
+ let mut _10: *const [i32; 10]; // in scope 0 at $DIR/address_of.rs:+6:5: +6:6
+ let _11: *const [i32]; // in scope 0 at $DIR/address_of.rs:+7:5: +7:22
+ let mut _12: *const [i32; 10]; // in scope 0 at $DIR/address_of.rs:+7:5: +7:6
+ let _13: *const i32; // in scope 0 at $DIR/address_of.rs:+8:5: +8:20
+ let mut _14: *const [i32; 10]; // in scope 0 at $DIR/address_of.rs:+8:5: +8:6
+ let mut _18: *const [i32; 10]; // in scope 0 at $DIR/address_of.rs:+12:30: +12:31
+ let mut _20: *const [i32; 10]; // in scope 0 at $DIR/address_of.rs:+13:27: +13:28
+ let _21: *const [i32; 10]; // in scope 0 at $DIR/address_of.rs:+15:5: +15:18
+ let mut _22: *const [i32; 10]; // in scope 0 at $DIR/address_of.rs:+15:5: +15:18
+ let _23: *const [i32; 10]; // in scope 0 at $DIR/address_of.rs:+16:5: +16:26
+ let _24: *const dyn std::marker::Send; // in scope 0 at $DIR/address_of.rs:+17:5: +17:25
+ let mut _25: *const dyn std::marker::Send; // in scope 0 at $DIR/address_of.rs:+17:5: +17:25
+ let mut _26: *const [i32; 10]; // in scope 0 at $DIR/address_of.rs:+17:5: +17:6
+ let _27: *const [i32]; // in scope 0 at $DIR/address_of.rs:+18:5: +18:22
+ let mut _28: *const [i32; 10]; // in scope 0 at $DIR/address_of.rs:+18:5: +18:6
+ let mut _32: *const [i32; 10]; // in scope 0 at $DIR/address_of.rs:+22:30: +22:31
+ let mut _34: *const [i32; 10]; // in scope 0 at $DIR/address_of.rs:+23:27: +23:28
+ let _35: *mut [i32; 10]; // in scope 0 at $DIR/address_of.rs:+25:5: +25:16
+ let mut _36: *mut [i32; 10]; // in scope 0 at $DIR/address_of.rs:+25:5: +25:16
+ let _37: *mut [i32; 10]; // in scope 0 at $DIR/address_of.rs:+26:5: +26:24
+ let _38: *mut dyn std::marker::Send; // in scope 0 at $DIR/address_of.rs:+27:5: +27:23
+ let mut _39: *mut dyn std::marker::Send; // in scope 0 at $DIR/address_of.rs:+27:5: +27:23
+ let mut _40: *mut [i32; 10]; // in scope 0 at $DIR/address_of.rs:+27:5: +27:6
+ let _41: *mut [i32]; // in scope 0 at $DIR/address_of.rs:+28:5: +28:20
+ let mut _42: *mut [i32; 10]; // in scope 0 at $DIR/address_of.rs:+28:5: +28:6
+ let mut _46: *mut [i32; 10]; // in scope 0 at $DIR/address_of.rs:+32:28: +32:29
+ let mut _48: *mut [i32; 10]; // in scope 0 at $DIR/address_of.rs:+33:25: +33:26
scope 1 {
- debug y => _1; // in scope 1 at $DIR/address-of.rs:+1:9: +1:10
- let mut _3: &mut [i32; 10]; // in scope 1 at $DIR/address-of.rs:+2:9: +2:14
+ debug y => _1; // in scope 1 at $DIR/address_of.rs:+1:9: +1:10
+ let mut _3: &mut [i32; 10]; // in scope 1 at $DIR/address_of.rs:+2:9: +2:14
scope 2 {
- debug z => _3; // in scope 2 at $DIR/address-of.rs:+2:9: +2:14
- let _15: *const [i32; 10] as UserTypeProjection { base: UserType(2), projs: [] }; // in scope 2 at $DIR/address-of.rs:+10:9: +10:10
+ debug z => _3; // in scope 2 at $DIR/address_of.rs:+2:9: +2:14
+ let _15: *const [i32; 10] as UserTypeProjection { base: UserType(2), projs: [] }; // in scope 2 at $DIR/address_of.rs:+10:9: +10:10
scope 3 {
- debug p => _15; // in scope 3 at $DIR/address-of.rs:+10:9: +10:10
- let _16: *const [i32; 10] as UserTypeProjection { base: UserType(4), projs: [] }; // in scope 3 at $DIR/address-of.rs:+11:9: +11:10
+ debug p => _15; // in scope 3 at $DIR/address_of.rs:+10:9: +10:10
+ let _16: *const [i32; 10] as UserTypeProjection { base: UserType(4), projs: [] }; // in scope 3 at $DIR/address_of.rs:+11:9: +11:10
scope 4 {
- debug p => _16; // in scope 4 at $DIR/address-of.rs:+11:9: +11:10
- let _17: *const dyn std::marker::Send as UserTypeProjection { base: UserType(6), projs: [] }; // in scope 4 at $DIR/address-of.rs:+12:9: +12:10
+ debug p => _16; // in scope 4 at $DIR/address_of.rs:+11:9: +11:10
+ let _17: *const dyn std::marker::Send as UserTypeProjection { base: UserType(6), projs: [] }; // in scope 4 at $DIR/address_of.rs:+12:9: +12:10
scope 5 {
- debug p => _17; // in scope 5 at $DIR/address-of.rs:+12:9: +12:10
- let _19: *const [i32] as UserTypeProjection { base: UserType(8), projs: [] }; // in scope 5 at $DIR/address-of.rs:+13:9: +13:10
+ debug p => _17; // in scope 5 at $DIR/address_of.rs:+12:9: +12:10
+ let _19: *const [i32] as UserTypeProjection { base: UserType(8), projs: [] }; // in scope 5 at $DIR/address_of.rs:+13:9: +13:10
scope 6 {
- debug p => _19; // in scope 6 at $DIR/address-of.rs:+13:9: +13:10
- let _29: *const [i32; 10] as UserTypeProjection { base: UserType(12), projs: [] }; // in scope 6 at $DIR/address-of.rs:+20:9: +20:10
+ debug p => _19; // in scope 6 at $DIR/address_of.rs:+13:9: +13:10
+ let _29: *const [i32; 10] as UserTypeProjection { base: UserType(12), projs: [] }; // in scope 6 at $DIR/address_of.rs:+20:9: +20:10
scope 7 {
- debug p => _29; // in scope 7 at $DIR/address-of.rs:+20:9: +20:10
- let _30: *const [i32; 10] as UserTypeProjection { base: UserType(14), projs: [] }; // in scope 7 at $DIR/address-of.rs:+21:9: +21:10
+ debug p => _29; // in scope 7 at $DIR/address_of.rs:+20:9: +20:10
+ let _30: *const [i32; 10] as UserTypeProjection { base: UserType(14), projs: [] }; // in scope 7 at $DIR/address_of.rs:+21:9: +21:10
scope 8 {
- debug p => _30; // in scope 8 at $DIR/address-of.rs:+21:9: +21:10
- let _31: *const dyn std::marker::Send as UserTypeProjection { base: UserType(16), projs: [] }; // in scope 8 at $DIR/address-of.rs:+22:9: +22:10
+ debug p => _30; // in scope 8 at $DIR/address_of.rs:+21:9: +21:10
+ let _31: *const dyn std::marker::Send as UserTypeProjection { base: UserType(16), projs: [] }; // in scope 8 at $DIR/address_of.rs:+22:9: +22:10
scope 9 {
- debug p => _31; // in scope 9 at $DIR/address-of.rs:+22:9: +22:10
- let _33: *const [i32] as UserTypeProjection { base: UserType(18), projs: [] }; // in scope 9 at $DIR/address-of.rs:+23:9: +23:10
+ debug p => _31; // in scope 9 at $DIR/address_of.rs:+22:9: +22:10
+ let _33: *const [i32] as UserTypeProjection { base: UserType(18), projs: [] }; // in scope 9 at $DIR/address_of.rs:+23:9: +23:10
scope 10 {
- debug p => _33; // in scope 10 at $DIR/address-of.rs:+23:9: +23:10
- let _43: *mut [i32; 10] as UserTypeProjection { base: UserType(22), projs: [] }; // in scope 10 at $DIR/address-of.rs:+30:9: +30:10
+ debug p => _33; // in scope 10 at $DIR/address_of.rs:+23:9: +23:10
+ let _43: *mut [i32; 10] as UserTypeProjection { base: UserType(22), projs: [] }; // in scope 10 at $DIR/address_of.rs:+30:9: +30:10
scope 11 {
- debug p => _43; // in scope 11 at $DIR/address-of.rs:+30:9: +30:10
- let _44: *mut [i32; 10] as UserTypeProjection { base: UserType(24), projs: [] }; // in scope 11 at $DIR/address-of.rs:+31:9: +31:10
+ debug p => _43; // in scope 11 at $DIR/address_of.rs:+30:9: +30:10
+ let _44: *mut [i32; 10] as UserTypeProjection { base: UserType(24), projs: [] }; // in scope 11 at $DIR/address_of.rs:+31:9: +31:10
scope 12 {
- debug p => _44; // in scope 12 at $DIR/address-of.rs:+31:9: +31:10
- let _45: *mut dyn std::marker::Send as UserTypeProjection { base: UserType(26), projs: [] }; // in scope 12 at $DIR/address-of.rs:+32:9: +32:10
+ debug p => _44; // in scope 12 at $DIR/address_of.rs:+31:9: +31:10
+ let _45: *mut dyn std::marker::Send as UserTypeProjection { base: UserType(26), projs: [] }; // in scope 12 at $DIR/address_of.rs:+32:9: +32:10
scope 13 {
- debug p => _45; // in scope 13 at $DIR/address-of.rs:+32:9: +32:10
- let _47: *mut [i32] as UserTypeProjection { base: UserType(28), projs: [] }; // in scope 13 at $DIR/address-of.rs:+33:9: +33:10
+ debug p => _45; // in scope 13 at $DIR/address_of.rs:+32:9: +32:10
+ let _47: *mut [i32] as UserTypeProjection { base: UserType(28), projs: [] }; // in scope 13 at $DIR/address_of.rs:+33:9: +33:10
scope 14 {
- debug p => _47; // in scope 14 at $DIR/address-of.rs:+33:9: +33:10
+ debug p => _47; // in scope 14 at $DIR/address_of.rs:+33:9: +33:10
}
}
}
}
bb0: {
- StorageLive(_1); // scope 0 at $DIR/address-of.rs:+1:9: +1:10
- StorageLive(_2); // scope 0 at $DIR/address-of.rs:+1:14: +1:21
- _2 = [const 0_i32; 10]; // scope 0 at $DIR/address-of.rs:+1:14: +1:21
- _1 = &_2; // scope 0 at $DIR/address-of.rs:+1:13: +1:21
- FakeRead(ForLet(None), _1); // scope 0 at $DIR/address-of.rs:+1:9: +1:10
- StorageLive(_3); // scope 1 at $DIR/address-of.rs:+2:9: +2:14
- StorageLive(_4); // scope 1 at $DIR/address-of.rs:+2:22: +2:29
- _4 = [const 0_i32; 10]; // scope 1 at $DIR/address-of.rs:+2:22: +2:29
- _3 = &mut _4; // scope 1 at $DIR/address-of.rs:+2:17: +2:29
- FakeRead(ForLet(None), _3); // scope 1 at $DIR/address-of.rs:+2:9: +2:14
- StorageLive(_5); // scope 2 at $DIR/address-of.rs:+4:5: +4:18
- StorageLive(_6); // scope 2 at $DIR/address-of.rs:+4:5: +4:18
- _6 = &raw const (*_1); // scope 2 at $DIR/address-of.rs:+4:5: +4:6
- AscribeUserType(_6, o, UserTypeProjection { base: UserType(0), projs: [] }); // scope 2 at $DIR/address-of.rs:+4:5: +4:18
- _5 = _6; // scope 2 at $DIR/address-of.rs:+4:5: +4:18
- StorageDead(_6); // scope 2 at $DIR/address-of.rs:+4:18: +4:19
- StorageDead(_5); // scope 2 at $DIR/address-of.rs:+4:18: +4:19
- StorageLive(_7); // scope 2 at $DIR/address-of.rs:+5:5: +5:26
- _7 = &raw const (*_1); // scope 2 at $DIR/address-of.rs:+5:5: +5:6
- StorageDead(_7); // scope 2 at $DIR/address-of.rs:+5:26: +5:27
- StorageLive(_8); // scope 2 at $DIR/address-of.rs:+6:5: +6:25
- StorageLive(_9); // scope 2 at $DIR/address-of.rs:+6:5: +6:25
- StorageLive(_10); // scope 2 at $DIR/address-of.rs:+6:5: +6:6
- _10 = &raw const (*_1); // scope 2 at $DIR/address-of.rs:+6:5: +6:6
- _9 = move _10 as *const dyn std::marker::Send (Pointer(Unsize)); // scope 2 at $DIR/address-of.rs:+6:5: +6:6
- StorageDead(_10); // scope 2 at $DIR/address-of.rs:+6:5: +6:6
- AscribeUserType(_9, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 2 at $DIR/address-of.rs:+6:5: +6:25
- _8 = _9; // scope 2 at $DIR/address-of.rs:+6:5: +6:25
- StorageDead(_9); // scope 2 at $DIR/address-of.rs:+6:25: +6:26
- StorageDead(_8); // scope 2 at $DIR/address-of.rs:+6:25: +6:26
- StorageLive(_11); // scope 2 at $DIR/address-of.rs:+7:5: +7:22
- StorageLive(_12); // scope 2 at $DIR/address-of.rs:+7:5: +7:6
- _12 = &raw const (*_1); // scope 2 at $DIR/address-of.rs:+7:5: +7:6
- _11 = move _12 as *const [i32] (Pointer(Unsize)); // scope 2 at $DIR/address-of.rs:+7:5: +7:6
- StorageDead(_12); // scope 2 at $DIR/address-of.rs:+7:5: +7:6
- StorageDead(_11); // scope 2 at $DIR/address-of.rs:+7:22: +7:23
- StorageLive(_13); // scope 2 at $DIR/address-of.rs:+8:5: +8:20
- StorageLive(_14); // scope 2 at $DIR/address-of.rs:+8:5: +8:6
- _14 = &raw const (*_1); // scope 2 at $DIR/address-of.rs:+8:5: +8:6
- _13 = move _14 as *const i32 (Pointer(ArrayToPointer)); // scope 2 at $DIR/address-of.rs:+8:5: +8:20
- StorageDead(_14); // scope 2 at $DIR/address-of.rs:+8:19: +8:20
- StorageDead(_13); // scope 2 at $DIR/address-of.rs:+8:20: +8:21
- StorageLive(_15); // scope 2 at $DIR/address-of.rs:+10:9: +10:10
- _15 = &raw const (*_1); // scope 2 at $DIR/address-of.rs:+10:23: +10:24
- FakeRead(ForLet(None), _15); // scope 2 at $DIR/address-of.rs:+10:9: +10:10
- AscribeUserType(_15, o, UserTypeProjection { base: UserType(3), projs: [] }); // scope 2 at $DIR/address-of.rs:+10:12: +10:20
- StorageLive(_16); // scope 3 at $DIR/address-of.rs:+11:9: +11:10
- _16 = &raw const (*_1); // scope 3 at $DIR/address-of.rs:+11:31: +11:32
- FakeRead(ForLet(None), _16); // scope 3 at $DIR/address-of.rs:+11:9: +11:10
- AscribeUserType(_16, o, UserTypeProjection { base: UserType(5), projs: [] }); // scope 3 at $DIR/address-of.rs:+11:12: +11:28
- StorageLive(_17); // scope 4 at $DIR/address-of.rs:+12:9: +12:10
- StorageLive(_18); // scope 4 at $DIR/address-of.rs:+12:30: +12:31
- _18 = &raw const (*_1); // scope 4 at $DIR/address-of.rs:+12:30: +12:31
- _17 = move _18 as *const dyn std::marker::Send (Pointer(Unsize)); // scope 4 at $DIR/address-of.rs:+12:30: +12:31
- StorageDead(_18); // scope 4 at $DIR/address-of.rs:+12:30: +12:31
- FakeRead(ForLet(None), _17); // scope 4 at $DIR/address-of.rs:+12:9: +12:10
- AscribeUserType(_17, o, UserTypeProjection { base: UserType(7), projs: [] }); // scope 4 at $DIR/address-of.rs:+12:12: +12:27
- StorageLive(_19); // scope 5 at $DIR/address-of.rs:+13:9: +13:10
- StorageLive(_20); // scope 5 at $DIR/address-of.rs:+13:27: +13:28
- _20 = &raw const (*_1); // scope 5 at $DIR/address-of.rs:+13:27: +13:28
- _19 = move _20 as *const [i32] (Pointer(Unsize)); // scope 5 at $DIR/address-of.rs:+13:27: +13:28
- StorageDead(_20); // scope 5 at $DIR/address-of.rs:+13:27: +13:28
- FakeRead(ForLet(None), _19); // scope 5 at $DIR/address-of.rs:+13:9: +13:10
- AscribeUserType(_19, o, UserTypeProjection { base: UserType(9), projs: [] }); // scope 5 at $DIR/address-of.rs:+13:12: +13:24
- StorageLive(_21); // scope 6 at $DIR/address-of.rs:+15:5: +15:18
- StorageLive(_22); // scope 6 at $DIR/address-of.rs:+15:5: +15:18
- _22 = &raw const (*_3); // scope 6 at $DIR/address-of.rs:+15:5: +15:6
- AscribeUserType(_22, o, UserTypeProjection { base: UserType(10), projs: [] }); // scope 6 at $DIR/address-of.rs:+15:5: +15:18
- _21 = _22; // scope 6 at $DIR/address-of.rs:+15:5: +15:18
- StorageDead(_22); // scope 6 at $DIR/address-of.rs:+15:18: +15:19
- StorageDead(_21); // scope 6 at $DIR/address-of.rs:+15:18: +15:19
- StorageLive(_23); // scope 6 at $DIR/address-of.rs:+16:5: +16:26
- _23 = &raw const (*_3); // scope 6 at $DIR/address-of.rs:+16:5: +16:6
- StorageDead(_23); // scope 6 at $DIR/address-of.rs:+16:26: +16:27
- StorageLive(_24); // scope 6 at $DIR/address-of.rs:+17:5: +17:25
- StorageLive(_25); // scope 6 at $DIR/address-of.rs:+17:5: +17:25
- StorageLive(_26); // scope 6 at $DIR/address-of.rs:+17:5: +17:6
- _26 = &raw const (*_3); // scope 6 at $DIR/address-of.rs:+17:5: +17:6
- _25 = move _26 as *const dyn std::marker::Send (Pointer(Unsize)); // scope 6 at $DIR/address-of.rs:+17:5: +17:6
- StorageDead(_26); // scope 6 at $DIR/address-of.rs:+17:5: +17:6
- AscribeUserType(_25, o, UserTypeProjection { base: UserType(11), projs: [] }); // scope 6 at $DIR/address-of.rs:+17:5: +17:25
- _24 = _25; // scope 6 at $DIR/address-of.rs:+17:5: +17:25
- StorageDead(_25); // scope 6 at $DIR/address-of.rs:+17:25: +17:26
- StorageDead(_24); // scope 6 at $DIR/address-of.rs:+17:25: +17:26
- StorageLive(_27); // scope 6 at $DIR/address-of.rs:+18:5: +18:22
- StorageLive(_28); // scope 6 at $DIR/address-of.rs:+18:5: +18:6
- _28 = &raw const (*_3); // scope 6 at $DIR/address-of.rs:+18:5: +18:6
- _27 = move _28 as *const [i32] (Pointer(Unsize)); // scope 6 at $DIR/address-of.rs:+18:5: +18:6
- StorageDead(_28); // scope 6 at $DIR/address-of.rs:+18:5: +18:6
- StorageDead(_27); // scope 6 at $DIR/address-of.rs:+18:22: +18:23
- StorageLive(_29); // scope 6 at $DIR/address-of.rs:+20:9: +20:10
- _29 = &raw const (*_3); // scope 6 at $DIR/address-of.rs:+20:23: +20:24
- FakeRead(ForLet(None), _29); // scope 6 at $DIR/address-of.rs:+20:9: +20:10
- AscribeUserType(_29, o, UserTypeProjection { base: UserType(13), projs: [] }); // scope 6 at $DIR/address-of.rs:+20:12: +20:20
- StorageLive(_30); // scope 7 at $DIR/address-of.rs:+21:9: +21:10
- _30 = &raw const (*_3); // scope 7 at $DIR/address-of.rs:+21:31: +21:32
- FakeRead(ForLet(None), _30); // scope 7 at $DIR/address-of.rs:+21:9: +21:10
- AscribeUserType(_30, o, UserTypeProjection { base: UserType(15), projs: [] }); // scope 7 at $DIR/address-of.rs:+21:12: +21:28
- StorageLive(_31); // scope 8 at $DIR/address-of.rs:+22:9: +22:10
- StorageLive(_32); // scope 8 at $DIR/address-of.rs:+22:30: +22:31
- _32 = &raw const (*_3); // scope 8 at $DIR/address-of.rs:+22:30: +22:31
- _31 = move _32 as *const dyn std::marker::Send (Pointer(Unsize)); // scope 8 at $DIR/address-of.rs:+22:30: +22:31
- StorageDead(_32); // scope 8 at $DIR/address-of.rs:+22:30: +22:31
- FakeRead(ForLet(None), _31); // scope 8 at $DIR/address-of.rs:+22:9: +22:10
- AscribeUserType(_31, o, UserTypeProjection { base: UserType(17), projs: [] }); // scope 8 at $DIR/address-of.rs:+22:12: +22:27
- StorageLive(_33); // scope 9 at $DIR/address-of.rs:+23:9: +23:10
- StorageLive(_34); // scope 9 at $DIR/address-of.rs:+23:27: +23:28
- _34 = &raw const (*_3); // scope 9 at $DIR/address-of.rs:+23:27: +23:28
- _33 = move _34 as *const [i32] (Pointer(Unsize)); // scope 9 at $DIR/address-of.rs:+23:27: +23:28
- StorageDead(_34); // scope 9 at $DIR/address-of.rs:+23:27: +23:28
- FakeRead(ForLet(None), _33); // scope 9 at $DIR/address-of.rs:+23:9: +23:10
- AscribeUserType(_33, o, UserTypeProjection { base: UserType(19), projs: [] }); // scope 9 at $DIR/address-of.rs:+23:12: +23:24
- StorageLive(_35); // scope 10 at $DIR/address-of.rs:+25:5: +25:16
- StorageLive(_36); // scope 10 at $DIR/address-of.rs:+25:5: +25:16
- _36 = &raw mut (*_3); // scope 10 at $DIR/address-of.rs:+25:5: +25:6
- AscribeUserType(_36, o, UserTypeProjection { base: UserType(20), projs: [] }); // scope 10 at $DIR/address-of.rs:+25:5: +25:16
- _35 = _36; // scope 10 at $DIR/address-of.rs:+25:5: +25:16
- StorageDead(_36); // scope 10 at $DIR/address-of.rs:+25:16: +25:17
- StorageDead(_35); // scope 10 at $DIR/address-of.rs:+25:16: +25:17
- StorageLive(_37); // scope 10 at $DIR/address-of.rs:+26:5: +26:24
- _37 = &raw mut (*_3); // scope 10 at $DIR/address-of.rs:+26:5: +26:6
- StorageDead(_37); // scope 10 at $DIR/address-of.rs:+26:24: +26:25
- StorageLive(_38); // scope 10 at $DIR/address-of.rs:+27:5: +27:23
- StorageLive(_39); // scope 10 at $DIR/address-of.rs:+27:5: +27:23
- StorageLive(_40); // scope 10 at $DIR/address-of.rs:+27:5: +27:6
- _40 = &raw mut (*_3); // scope 10 at $DIR/address-of.rs:+27:5: +27:6
- _39 = move _40 as *mut dyn std::marker::Send (Pointer(Unsize)); // scope 10 at $DIR/address-of.rs:+27:5: +27:6
- StorageDead(_40); // scope 10 at $DIR/address-of.rs:+27:5: +27:6
- AscribeUserType(_39, o, UserTypeProjection { base: UserType(21), projs: [] }); // scope 10 at $DIR/address-of.rs:+27:5: +27:23
- _38 = _39; // scope 10 at $DIR/address-of.rs:+27:5: +27:23
- StorageDead(_39); // scope 10 at $DIR/address-of.rs:+27:23: +27:24
- StorageDead(_38); // scope 10 at $DIR/address-of.rs:+27:23: +27:24
- StorageLive(_41); // scope 10 at $DIR/address-of.rs:+28:5: +28:20
- StorageLive(_42); // scope 10 at $DIR/address-of.rs:+28:5: +28:6
- _42 = &raw mut (*_3); // scope 10 at $DIR/address-of.rs:+28:5: +28:6
- _41 = move _42 as *mut [i32] (Pointer(Unsize)); // scope 10 at $DIR/address-of.rs:+28:5: +28:6
- StorageDead(_42); // scope 10 at $DIR/address-of.rs:+28:5: +28:6
- StorageDead(_41); // scope 10 at $DIR/address-of.rs:+28:20: +28:21
- StorageLive(_43); // scope 10 at $DIR/address-of.rs:+30:9: +30:10
- _43 = &raw mut (*_3); // scope 10 at $DIR/address-of.rs:+30:21: +30:22
- FakeRead(ForLet(None), _43); // scope 10 at $DIR/address-of.rs:+30:9: +30:10
- AscribeUserType(_43, o, UserTypeProjection { base: UserType(23), projs: [] }); // scope 10 at $DIR/address-of.rs:+30:12: +30:18
- StorageLive(_44); // scope 11 at $DIR/address-of.rs:+31:9: +31:10
- _44 = &raw mut (*_3); // scope 11 at $DIR/address-of.rs:+31:29: +31:30
- FakeRead(ForLet(None), _44); // scope 11 at $DIR/address-of.rs:+31:9: +31:10
- AscribeUserType(_44, o, UserTypeProjection { base: UserType(25), projs: [] }); // scope 11 at $DIR/address-of.rs:+31:12: +31:26
- StorageLive(_45); // scope 12 at $DIR/address-of.rs:+32:9: +32:10
- StorageLive(_46); // scope 12 at $DIR/address-of.rs:+32:28: +32:29
- _46 = &raw mut (*_3); // scope 12 at $DIR/address-of.rs:+32:28: +32:29
- _45 = move _46 as *mut dyn std::marker::Send (Pointer(Unsize)); // scope 12 at $DIR/address-of.rs:+32:28: +32:29
- StorageDead(_46); // scope 12 at $DIR/address-of.rs:+32:28: +32:29
- FakeRead(ForLet(None), _45); // scope 12 at $DIR/address-of.rs:+32:9: +32:10
- AscribeUserType(_45, o, UserTypeProjection { base: UserType(27), projs: [] }); // scope 12 at $DIR/address-of.rs:+32:12: +32:25
- StorageLive(_47); // scope 13 at $DIR/address-of.rs:+33:9: +33:10
- StorageLive(_48); // scope 13 at $DIR/address-of.rs:+33:25: +33:26
- _48 = &raw mut (*_3); // scope 13 at $DIR/address-of.rs:+33:25: +33:26
- _47 = move _48 as *mut [i32] (Pointer(Unsize)); // scope 13 at $DIR/address-of.rs:+33:25: +33:26
- StorageDead(_48); // scope 13 at $DIR/address-of.rs:+33:25: +33:26
- FakeRead(ForLet(None), _47); // scope 13 at $DIR/address-of.rs:+33:9: +33:10
- AscribeUserType(_47, o, UserTypeProjection { base: UserType(29), projs: [] }); // scope 13 at $DIR/address-of.rs:+33:12: +33:22
- _0 = const (); // scope 0 at $DIR/address-of.rs:+0:26: +34:2
- StorageDead(_47); // scope 13 at $DIR/address-of.rs:+34:1: +34:2
- StorageDead(_45); // scope 12 at $DIR/address-of.rs:+34:1: +34:2
- StorageDead(_44); // scope 11 at $DIR/address-of.rs:+34:1: +34:2
- StorageDead(_43); // scope 10 at $DIR/address-of.rs:+34:1: +34:2
- StorageDead(_33); // scope 9 at $DIR/address-of.rs:+34:1: +34:2
- StorageDead(_31); // scope 8 at $DIR/address-of.rs:+34:1: +34:2
- StorageDead(_30); // scope 7 at $DIR/address-of.rs:+34:1: +34:2
- StorageDead(_29); // scope 6 at $DIR/address-of.rs:+34:1: +34:2
- StorageDead(_19); // scope 5 at $DIR/address-of.rs:+34:1: +34:2
- StorageDead(_17); // scope 4 at $DIR/address-of.rs:+34:1: +34:2
- StorageDead(_16); // scope 3 at $DIR/address-of.rs:+34:1: +34:2
- StorageDead(_15); // scope 2 at $DIR/address-of.rs:+34:1: +34:2
- StorageDead(_4); // scope 1 at $DIR/address-of.rs:+34:1: +34:2
- StorageDead(_3); // scope 1 at $DIR/address-of.rs:+34:1: +34:2
- StorageDead(_2); // scope 0 at $DIR/address-of.rs:+34:1: +34:2
- StorageDead(_1); // scope 0 at $DIR/address-of.rs:+34:1: +34:2
- return; // scope 0 at $DIR/address-of.rs:+34:2: +34:2
+ StorageLive(_1); // scope 0 at $DIR/address_of.rs:+1:9: +1:10
+ StorageLive(_2); // scope 0 at $DIR/address_of.rs:+1:14: +1:21
+ _2 = [const 0_i32; 10]; // scope 0 at $DIR/address_of.rs:+1:14: +1:21
+ _1 = &_2; // scope 0 at $DIR/address_of.rs:+1:13: +1:21
+ FakeRead(ForLet(None), _1); // scope 0 at $DIR/address_of.rs:+1:9: +1:10
+ StorageLive(_3); // scope 1 at $DIR/address_of.rs:+2:9: +2:14
+ StorageLive(_4); // scope 1 at $DIR/address_of.rs:+2:22: +2:29
+ _4 = [const 0_i32; 10]; // scope 1 at $DIR/address_of.rs:+2:22: +2:29
+ _3 = &mut _4; // scope 1 at $DIR/address_of.rs:+2:17: +2:29
+ FakeRead(ForLet(None), _3); // scope 1 at $DIR/address_of.rs:+2:9: +2:14
+ StorageLive(_5); // scope 2 at $DIR/address_of.rs:+4:5: +4:18
+ StorageLive(_6); // scope 2 at $DIR/address_of.rs:+4:5: +4:18
+ _6 = &raw const (*_1); // scope 2 at $DIR/address_of.rs:+4:5: +4:6
+ AscribeUserType(_6, o, UserTypeProjection { base: UserType(0), projs: [] }); // scope 2 at $DIR/address_of.rs:+4:5: +4:18
+ _5 = _6; // scope 2 at $DIR/address_of.rs:+4:5: +4:18
+ StorageDead(_6); // scope 2 at $DIR/address_of.rs:+4:18: +4:19
+ StorageDead(_5); // scope 2 at $DIR/address_of.rs:+4:18: +4:19
+ StorageLive(_7); // scope 2 at $DIR/address_of.rs:+5:5: +5:26
+ _7 = &raw const (*_1); // scope 2 at $DIR/address_of.rs:+5:5: +5:6
+ StorageDead(_7); // scope 2 at $DIR/address_of.rs:+5:26: +5:27
+ StorageLive(_8); // scope 2 at $DIR/address_of.rs:+6:5: +6:25
+ StorageLive(_9); // scope 2 at $DIR/address_of.rs:+6:5: +6:25
+ StorageLive(_10); // scope 2 at $DIR/address_of.rs:+6:5: +6:6
+ _10 = &raw const (*_1); // scope 2 at $DIR/address_of.rs:+6:5: +6:6
+ _9 = move _10 as *const dyn std::marker::Send (Pointer(Unsize)); // scope 2 at $DIR/address_of.rs:+6:5: +6:6
+ StorageDead(_10); // scope 2 at $DIR/address_of.rs:+6:5: +6:6
+ AscribeUserType(_9, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 2 at $DIR/address_of.rs:+6:5: +6:25
+ _8 = _9; // scope 2 at $DIR/address_of.rs:+6:5: +6:25
+ StorageDead(_9); // scope 2 at $DIR/address_of.rs:+6:25: +6:26
+ StorageDead(_8); // scope 2 at $DIR/address_of.rs:+6:25: +6:26
+ StorageLive(_11); // scope 2 at $DIR/address_of.rs:+7:5: +7:22
+ StorageLive(_12); // scope 2 at $DIR/address_of.rs:+7:5: +7:6
+ _12 = &raw const (*_1); // scope 2 at $DIR/address_of.rs:+7:5: +7:6
+ _11 = move _12 as *const [i32] (Pointer(Unsize)); // scope 2 at $DIR/address_of.rs:+7:5: +7:6
+ StorageDead(_12); // scope 2 at $DIR/address_of.rs:+7:5: +7:6
+ StorageDead(_11); // scope 2 at $DIR/address_of.rs:+7:22: +7:23
+ StorageLive(_13); // scope 2 at $DIR/address_of.rs:+8:5: +8:20
+ StorageLive(_14); // scope 2 at $DIR/address_of.rs:+8:5: +8:6
+ _14 = &raw const (*_1); // scope 2 at $DIR/address_of.rs:+8:5: +8:6
+ _13 = move _14 as *const i32 (Pointer(ArrayToPointer)); // scope 2 at $DIR/address_of.rs:+8:5: +8:20
+ StorageDead(_14); // scope 2 at $DIR/address_of.rs:+8:19: +8:20
+ StorageDead(_13); // scope 2 at $DIR/address_of.rs:+8:20: +8:21
+ StorageLive(_15); // scope 2 at $DIR/address_of.rs:+10:9: +10:10
+ _15 = &raw const (*_1); // scope 2 at $DIR/address_of.rs:+10:23: +10:24
+ FakeRead(ForLet(None), _15); // scope 2 at $DIR/address_of.rs:+10:9: +10:10
+ AscribeUserType(_15, o, UserTypeProjection { base: UserType(3), projs: [] }); // scope 2 at $DIR/address_of.rs:+10:12: +10:20
+ StorageLive(_16); // scope 3 at $DIR/address_of.rs:+11:9: +11:10
+ _16 = &raw const (*_1); // scope 3 at $DIR/address_of.rs:+11:31: +11:32
+ FakeRead(ForLet(None), _16); // scope 3 at $DIR/address_of.rs:+11:9: +11:10
+ AscribeUserType(_16, o, UserTypeProjection { base: UserType(5), projs: [] }); // scope 3 at $DIR/address_of.rs:+11:12: +11:28
+ StorageLive(_17); // scope 4 at $DIR/address_of.rs:+12:9: +12:10
+ StorageLive(_18); // scope 4 at $DIR/address_of.rs:+12:30: +12:31
+ _18 = &raw const (*_1); // scope 4 at $DIR/address_of.rs:+12:30: +12:31
+ _17 = move _18 as *const dyn std::marker::Send (Pointer(Unsize)); // scope 4 at $DIR/address_of.rs:+12:30: +12:31
+ StorageDead(_18); // scope 4 at $DIR/address_of.rs:+12:30: +12:31
+ FakeRead(ForLet(None), _17); // scope 4 at $DIR/address_of.rs:+12:9: +12:10
+ AscribeUserType(_17, o, UserTypeProjection { base: UserType(7), projs: [] }); // scope 4 at $DIR/address_of.rs:+12:12: +12:27
+ StorageLive(_19); // scope 5 at $DIR/address_of.rs:+13:9: +13:10
+ StorageLive(_20); // scope 5 at $DIR/address_of.rs:+13:27: +13:28
+ _20 = &raw const (*_1); // scope 5 at $DIR/address_of.rs:+13:27: +13:28
+ _19 = move _20 as *const [i32] (Pointer(Unsize)); // scope 5 at $DIR/address_of.rs:+13:27: +13:28
+ StorageDead(_20); // scope 5 at $DIR/address_of.rs:+13:27: +13:28
+ FakeRead(ForLet(None), _19); // scope 5 at $DIR/address_of.rs:+13:9: +13:10
+ AscribeUserType(_19, o, UserTypeProjection { base: UserType(9), projs: [] }); // scope 5 at $DIR/address_of.rs:+13:12: +13:24
+ StorageLive(_21); // scope 6 at $DIR/address_of.rs:+15:5: +15:18
+ StorageLive(_22); // scope 6 at $DIR/address_of.rs:+15:5: +15:18
+ _22 = &raw const (*_3); // scope 6 at $DIR/address_of.rs:+15:5: +15:6
+ AscribeUserType(_22, o, UserTypeProjection { base: UserType(10), projs: [] }); // scope 6 at $DIR/address_of.rs:+15:5: +15:18
+ _21 = _22; // scope 6 at $DIR/address_of.rs:+15:5: +15:18
+ StorageDead(_22); // scope 6 at $DIR/address_of.rs:+15:18: +15:19
+ StorageDead(_21); // scope 6 at $DIR/address_of.rs:+15:18: +15:19
+ StorageLive(_23); // scope 6 at $DIR/address_of.rs:+16:5: +16:26
+ _23 = &raw const (*_3); // scope 6 at $DIR/address_of.rs:+16:5: +16:6
+ StorageDead(_23); // scope 6 at $DIR/address_of.rs:+16:26: +16:27
+ StorageLive(_24); // scope 6 at $DIR/address_of.rs:+17:5: +17:25
+ StorageLive(_25); // scope 6 at $DIR/address_of.rs:+17:5: +17:25
+ StorageLive(_26); // scope 6 at $DIR/address_of.rs:+17:5: +17:6
+ _26 = &raw const (*_3); // scope 6 at $DIR/address_of.rs:+17:5: +17:6
+ _25 = move _26 as *const dyn std::marker::Send (Pointer(Unsize)); // scope 6 at $DIR/address_of.rs:+17:5: +17:6
+ StorageDead(_26); // scope 6 at $DIR/address_of.rs:+17:5: +17:6
+ AscribeUserType(_25, o, UserTypeProjection { base: UserType(11), projs: [] }); // scope 6 at $DIR/address_of.rs:+17:5: +17:25
+ _24 = _25; // scope 6 at $DIR/address_of.rs:+17:5: +17:25
+ StorageDead(_25); // scope 6 at $DIR/address_of.rs:+17:25: +17:26
+ StorageDead(_24); // scope 6 at $DIR/address_of.rs:+17:25: +17:26
+ StorageLive(_27); // scope 6 at $DIR/address_of.rs:+18:5: +18:22
+ StorageLive(_28); // scope 6 at $DIR/address_of.rs:+18:5: +18:6
+ _28 = &raw const (*_3); // scope 6 at $DIR/address_of.rs:+18:5: +18:6
+ _27 = move _28 as *const [i32] (Pointer(Unsize)); // scope 6 at $DIR/address_of.rs:+18:5: +18:6
+ StorageDead(_28); // scope 6 at $DIR/address_of.rs:+18:5: +18:6
+ StorageDead(_27); // scope 6 at $DIR/address_of.rs:+18:22: +18:23
+ StorageLive(_29); // scope 6 at $DIR/address_of.rs:+20:9: +20:10
+ _29 = &raw const (*_3); // scope 6 at $DIR/address_of.rs:+20:23: +20:24
+ FakeRead(ForLet(None), _29); // scope 6 at $DIR/address_of.rs:+20:9: +20:10
+ AscribeUserType(_29, o, UserTypeProjection { base: UserType(13), projs: [] }); // scope 6 at $DIR/address_of.rs:+20:12: +20:20
+ StorageLive(_30); // scope 7 at $DIR/address_of.rs:+21:9: +21:10
+ _30 = &raw const (*_3); // scope 7 at $DIR/address_of.rs:+21:31: +21:32
+ FakeRead(ForLet(None), _30); // scope 7 at $DIR/address_of.rs:+21:9: +21:10
+ AscribeUserType(_30, o, UserTypeProjection { base: UserType(15), projs: [] }); // scope 7 at $DIR/address_of.rs:+21:12: +21:28
+ StorageLive(_31); // scope 8 at $DIR/address_of.rs:+22:9: +22:10
+ StorageLive(_32); // scope 8 at $DIR/address_of.rs:+22:30: +22:31
+ _32 = &raw const (*_3); // scope 8 at $DIR/address_of.rs:+22:30: +22:31
+ _31 = move _32 as *const dyn std::marker::Send (Pointer(Unsize)); // scope 8 at $DIR/address_of.rs:+22:30: +22:31
+ StorageDead(_32); // scope 8 at $DIR/address_of.rs:+22:30: +22:31
+ FakeRead(ForLet(None), _31); // scope 8 at $DIR/address_of.rs:+22:9: +22:10
+ AscribeUserType(_31, o, UserTypeProjection { base: UserType(17), projs: [] }); // scope 8 at $DIR/address_of.rs:+22:12: +22:27
+ StorageLive(_33); // scope 9 at $DIR/address_of.rs:+23:9: +23:10
+ StorageLive(_34); // scope 9 at $DIR/address_of.rs:+23:27: +23:28
+ _34 = &raw const (*_3); // scope 9 at $DIR/address_of.rs:+23:27: +23:28
+ _33 = move _34 as *const [i32] (Pointer(Unsize)); // scope 9 at $DIR/address_of.rs:+23:27: +23:28
+ StorageDead(_34); // scope 9 at $DIR/address_of.rs:+23:27: +23:28
+ FakeRead(ForLet(None), _33); // scope 9 at $DIR/address_of.rs:+23:9: +23:10
+ AscribeUserType(_33, o, UserTypeProjection { base: UserType(19), projs: [] }); // scope 9 at $DIR/address_of.rs:+23:12: +23:24
+ StorageLive(_35); // scope 10 at $DIR/address_of.rs:+25:5: +25:16
+ StorageLive(_36); // scope 10 at $DIR/address_of.rs:+25:5: +25:16
+ _36 = &raw mut (*_3); // scope 10 at $DIR/address_of.rs:+25:5: +25:6
+ AscribeUserType(_36, o, UserTypeProjection { base: UserType(20), projs: [] }); // scope 10 at $DIR/address_of.rs:+25:5: +25:16
+ _35 = _36; // scope 10 at $DIR/address_of.rs:+25:5: +25:16
+ StorageDead(_36); // scope 10 at $DIR/address_of.rs:+25:16: +25:17
+ StorageDead(_35); // scope 10 at $DIR/address_of.rs:+25:16: +25:17
+ StorageLive(_37); // scope 10 at $DIR/address_of.rs:+26:5: +26:24
+ _37 = &raw mut (*_3); // scope 10 at $DIR/address_of.rs:+26:5: +26:6
+ StorageDead(_37); // scope 10 at $DIR/address_of.rs:+26:24: +26:25
+ StorageLive(_38); // scope 10 at $DIR/address_of.rs:+27:5: +27:23
+ StorageLive(_39); // scope 10 at $DIR/address_of.rs:+27:5: +27:23
+ StorageLive(_40); // scope 10 at $DIR/address_of.rs:+27:5: +27:6
+ _40 = &raw mut (*_3); // scope 10 at $DIR/address_of.rs:+27:5: +27:6
+ _39 = move _40 as *mut dyn std::marker::Send (Pointer(Unsize)); // scope 10 at $DIR/address_of.rs:+27:5: +27:6
+ StorageDead(_40); // scope 10 at $DIR/address_of.rs:+27:5: +27:6
+ AscribeUserType(_39, o, UserTypeProjection { base: UserType(21), projs: [] }); // scope 10 at $DIR/address_of.rs:+27:5: +27:23
+ _38 = _39; // scope 10 at $DIR/address_of.rs:+27:5: +27:23
+ StorageDead(_39); // scope 10 at $DIR/address_of.rs:+27:23: +27:24
+ StorageDead(_38); // scope 10 at $DIR/address_of.rs:+27:23: +27:24
+ StorageLive(_41); // scope 10 at $DIR/address_of.rs:+28:5: +28:20
+ StorageLive(_42); // scope 10 at $DIR/address_of.rs:+28:5: +28:6
+ _42 = &raw mut (*_3); // scope 10 at $DIR/address_of.rs:+28:5: +28:6
+ _41 = move _42 as *mut [i32] (Pointer(Unsize)); // scope 10 at $DIR/address_of.rs:+28:5: +28:6
+ StorageDead(_42); // scope 10 at $DIR/address_of.rs:+28:5: +28:6
+ StorageDead(_41); // scope 10 at $DIR/address_of.rs:+28:20: +28:21
+ StorageLive(_43); // scope 10 at $DIR/address_of.rs:+30:9: +30:10
+ _43 = &raw mut (*_3); // scope 10 at $DIR/address_of.rs:+30:21: +30:22
+ FakeRead(ForLet(None), _43); // scope 10 at $DIR/address_of.rs:+30:9: +30:10
+ AscribeUserType(_43, o, UserTypeProjection { base: UserType(23), projs: [] }); // scope 10 at $DIR/address_of.rs:+30:12: +30:18
+ StorageLive(_44); // scope 11 at $DIR/address_of.rs:+31:9: +31:10
+ _44 = &raw mut (*_3); // scope 11 at $DIR/address_of.rs:+31:29: +31:30
+ FakeRead(ForLet(None), _44); // scope 11 at $DIR/address_of.rs:+31:9: +31:10
+ AscribeUserType(_44, o, UserTypeProjection { base: UserType(25), projs: [] }); // scope 11 at $DIR/address_of.rs:+31:12: +31:26
+ StorageLive(_45); // scope 12 at $DIR/address_of.rs:+32:9: +32:10
+ StorageLive(_46); // scope 12 at $DIR/address_of.rs:+32:28: +32:29
+ _46 = &raw mut (*_3); // scope 12 at $DIR/address_of.rs:+32:28: +32:29
+ _45 = move _46 as *mut dyn std::marker::Send (Pointer(Unsize)); // scope 12 at $DIR/address_of.rs:+32:28: +32:29
+ StorageDead(_46); // scope 12 at $DIR/address_of.rs:+32:28: +32:29
+ FakeRead(ForLet(None), _45); // scope 12 at $DIR/address_of.rs:+32:9: +32:10
+ AscribeUserType(_45, o, UserTypeProjection { base: UserType(27), projs: [] }); // scope 12 at $DIR/address_of.rs:+32:12: +32:25
+ StorageLive(_47); // scope 13 at $DIR/address_of.rs:+33:9: +33:10
+ StorageLive(_48); // scope 13 at $DIR/address_of.rs:+33:25: +33:26
+ _48 = &raw mut (*_3); // scope 13 at $DIR/address_of.rs:+33:25: +33:26
+ _47 = move _48 as *mut [i32] (Pointer(Unsize)); // scope 13 at $DIR/address_of.rs:+33:25: +33:26
+ StorageDead(_48); // scope 13 at $DIR/address_of.rs:+33:25: +33:26
+ FakeRead(ForLet(None), _47); // scope 13 at $DIR/address_of.rs:+33:9: +33:10
+ AscribeUserType(_47, o, UserTypeProjection { base: UserType(29), projs: [] }); // scope 13 at $DIR/address_of.rs:+33:12: +33:22
+ _0 = const (); // scope 0 at $DIR/address_of.rs:+0:26: +34:2
+ StorageDead(_47); // scope 13 at $DIR/address_of.rs:+34:1: +34:2
+ StorageDead(_45); // scope 12 at $DIR/address_of.rs:+34:1: +34:2
+ StorageDead(_44); // scope 11 at $DIR/address_of.rs:+34:1: +34:2
+ StorageDead(_43); // scope 10 at $DIR/address_of.rs:+34:1: +34:2
+ StorageDead(_33); // scope 9 at $DIR/address_of.rs:+34:1: +34:2
+ StorageDead(_31); // scope 8 at $DIR/address_of.rs:+34:1: +34:2
+ StorageDead(_30); // scope 7 at $DIR/address_of.rs:+34:1: +34:2
+ StorageDead(_29); // scope 6 at $DIR/address_of.rs:+34:1: +34:2
+ StorageDead(_19); // scope 5 at $DIR/address_of.rs:+34:1: +34:2
+ StorageDead(_17); // scope 4 at $DIR/address_of.rs:+34:1: +34:2
+ StorageDead(_16); // scope 3 at $DIR/address_of.rs:+34:1: +34:2
+ StorageDead(_15); // scope 2 at $DIR/address_of.rs:+34:1: +34:2
+ StorageDead(_4); // scope 1 at $DIR/address_of.rs:+34:1: +34:2
+ StorageDead(_3); // scope 1 at $DIR/address_of.rs:+34:1: +34:2
+ StorageDead(_2); // scope 0 at $DIR/address_of.rs:+34:1: +34:2
+ StorageDead(_1); // scope 0 at $DIR/address_of.rs:+34:1: +34:2
+ return; // scope 0 at $DIR/address_of.rs:+34:2: +34:2
}
}
// MIR for `borrow_and_cast` after SimplifyCfg-initial
fn borrow_and_cast(_1: i32) -> () {
- debug x => _1; // in scope 0 at $DIR/address-of.rs:+0:20: +0:25
- let mut _0: (); // return place in scope 0 at $DIR/address-of.rs:+0:32: +0:32
- let _2: *const i32; // in scope 0 at $DIR/address-of.rs:+1:9: +1:10
- let _3: &i32; // in scope 0 at $DIR/address-of.rs:+1:13: +1:15
- let _5: &mut i32; // in scope 0 at $DIR/address-of.rs:+2:13: +2:19
- let mut _7: &mut i32; // in scope 0 at $DIR/address-of.rs:+3:13: +3:19
+ debug x => _1; // in scope 0 at $DIR/address_of.rs:+0:20: +0:25
+ let mut _0: (); // return place in scope 0 at $DIR/address_of.rs:+0:32: +0:32
+ let _2: *const i32; // in scope 0 at $DIR/address_of.rs:+1:9: +1:10
+ let _3: &i32; // in scope 0 at $DIR/address_of.rs:+1:13: +1:15
+ let _5: &mut i32; // in scope 0 at $DIR/address_of.rs:+2:13: +2:19
+ let mut _7: &mut i32; // in scope 0 at $DIR/address_of.rs:+3:13: +3:19
scope 1 {
- debug p => _2; // in scope 1 at $DIR/address-of.rs:+1:9: +1:10
- let _4: *const i32; // in scope 1 at $DIR/address-of.rs:+2:9: +2:10
+ debug p => _2; // in scope 1 at $DIR/address_of.rs:+1:9: +1:10
+ let _4: *const i32; // in scope 1 at $DIR/address_of.rs:+2:9: +2:10
scope 2 {
- debug q => _4; // in scope 2 at $DIR/address-of.rs:+2:9: +2:10
- let _6: *mut i32; // in scope 2 at $DIR/address-of.rs:+3:9: +3:10
+ debug q => _4; // in scope 2 at $DIR/address_of.rs:+2:9: +2:10
+ let _6: *mut i32; // in scope 2 at $DIR/address_of.rs:+3:9: +3:10
scope 3 {
- debug r => _6; // in scope 3 at $DIR/address-of.rs:+3:9: +3:10
+ debug r => _6; // in scope 3 at $DIR/address_of.rs:+3:9: +3:10
}
}
}
bb0: {
- StorageLive(_2); // scope 0 at $DIR/address-of.rs:+1:9: +1:10
- StorageLive(_3); // scope 0 at $DIR/address-of.rs:+1:13: +1:15
- _3 = &_1; // scope 0 at $DIR/address-of.rs:+1:13: +1:15
- _2 = &raw const (*_3); // scope 0 at $DIR/address-of.rs:+1:13: +1:15
- FakeRead(ForLet(None), _2); // scope 0 at $DIR/address-of.rs:+1:9: +1:10
- StorageDead(_3); // scope 0 at $DIR/address-of.rs:+1:29: +1:30
- StorageLive(_4); // scope 1 at $DIR/address-of.rs:+2:9: +2:10
- StorageLive(_5); // scope 1 at $DIR/address-of.rs:+2:13: +2:19
- _5 = &mut _1; // scope 1 at $DIR/address-of.rs:+2:13: +2:19
- _4 = &raw const (*_5); // scope 1 at $DIR/address-of.rs:+2:13: +2:19
- FakeRead(ForLet(None), _4); // scope 1 at $DIR/address-of.rs:+2:9: +2:10
- StorageDead(_5); // scope 1 at $DIR/address-of.rs:+2:33: +2:34
- StorageLive(_6); // scope 2 at $DIR/address-of.rs:+3:9: +3:10
- StorageLive(_7); // scope 2 at $DIR/address-of.rs:+3:13: +3:19
- _7 = &mut _1; // scope 2 at $DIR/address-of.rs:+3:13: +3:19
- _6 = &raw mut (*_7); // scope 2 at $DIR/address-of.rs:+3:13: +3:19
- FakeRead(ForLet(None), _6); // scope 2 at $DIR/address-of.rs:+3:9: +3:10
- StorageDead(_7); // scope 2 at $DIR/address-of.rs:+3:31: +3:32
- _0 = const (); // scope 0 at $DIR/address-of.rs:+0:32: +4:2
- StorageDead(_6); // scope 2 at $DIR/address-of.rs:+4:1: +4:2
- StorageDead(_4); // scope 1 at $DIR/address-of.rs:+4:1: +4:2
- StorageDead(_2); // scope 0 at $DIR/address-of.rs:+4:1: +4:2
- return; // scope 0 at $DIR/address-of.rs:+4:2: +4:2
+ StorageLive(_2); // scope 0 at $DIR/address_of.rs:+1:9: +1:10
+ StorageLive(_3); // scope 0 at $DIR/address_of.rs:+1:13: +1:15
+ _3 = &_1; // scope 0 at $DIR/address_of.rs:+1:13: +1:15
+ _2 = &raw const (*_3); // scope 0 at $DIR/address_of.rs:+1:13: +1:15
+ FakeRead(ForLet(None), _2); // scope 0 at $DIR/address_of.rs:+1:9: +1:10
+ StorageDead(_3); // scope 0 at $DIR/address_of.rs:+1:29: +1:30
+ StorageLive(_4); // scope 1 at $DIR/address_of.rs:+2:9: +2:10
+ StorageLive(_5); // scope 1 at $DIR/address_of.rs:+2:13: +2:19
+ _5 = &mut _1; // scope 1 at $DIR/address_of.rs:+2:13: +2:19
+ _4 = &raw const (*_5); // scope 1 at $DIR/address_of.rs:+2:13: +2:19
+ FakeRead(ForLet(None), _4); // scope 1 at $DIR/address_of.rs:+2:9: +2:10
+ StorageDead(_5); // scope 1 at $DIR/address_of.rs:+2:33: +2:34
+ StorageLive(_6); // scope 2 at $DIR/address_of.rs:+3:9: +3:10
+ StorageLive(_7); // scope 2 at $DIR/address_of.rs:+3:13: +3:19
+ _7 = &mut _1; // scope 2 at $DIR/address_of.rs:+3:13: +3:19
+ _6 = &raw mut (*_7); // scope 2 at $DIR/address_of.rs:+3:13: +3:19
+ FakeRead(ForLet(None), _6); // scope 2 at $DIR/address_of.rs:+3:9: +3:10
+ StorageDead(_7); // scope 2 at $DIR/address_of.rs:+3:31: +3:32
+ _0 = const (); // scope 0 at $DIR/address_of.rs:+0:32: +4:2
+ StorageDead(_6); // scope 2 at $DIR/address_of.rs:+4:1: +4:2
+ StorageDead(_4); // scope 1 at $DIR/address_of.rs:+4:1: +4:2
+ StorageDead(_2); // scope 0 at $DIR/address_of.rs:+4:1: +4:2
+ return; // scope 0 at $DIR/address_of.rs:+4:2: +4:2
}
}
--- /dev/null
+// EMIT_MIR address_of.address_of_reborrow.SimplifyCfg-initial.after.mir
+
+fn address_of_reborrow() {
+ let y = &[0; 10];
+ let mut z = &mut [0; 10];
+
+ y as *const _;
+ y as *const [i32; 10];
+ y as *const dyn Send;
+ y as *const [i32];
+ y as *const i32; // This is a cast, not a coercion
+
+ let p: *const _ = y;
+ let p: *const [i32; 10] = y;
+ let p: *const dyn Send = y;
+ let p: *const [i32] = y;
+
+ z as *const _;
+ z as *const [i32; 10];
+ z as *const dyn Send;
+ z as *const [i32];
+
+ let p: *const _ = z;
+ let p: *const [i32; 10] = z;
+ let p: *const dyn Send = z;
+ let p: *const [i32] = z;
+
+ z as *mut _;
+ z as *mut [i32; 10];
+ z as *mut dyn Send;
+ z as *mut [i32];
+
+ let p: *mut _ = z;
+ let p: *mut [i32; 10] = z;
+ let p: *mut dyn Send = z;
+ let p: *mut [i32] = z;
+}
+
+// The normal borrows here should be preserved
+// EMIT_MIR address_of.borrow_and_cast.SimplifyCfg-initial.after.mir
+fn borrow_and_cast(mut x: i32) {
+ let p = &x as *const i32;
+ let q = &mut x as *const i32;
+ let r = &mut x as *mut i32;
+}
+
+fn main() {}
+++ /dev/null
-// Retagging (from Stacked Borrows) relies on the array index being a fresh
-// temporary, so that side-effects cannot change it.
-// Test that this is indeed the case.
-
-unsafe fn foo(z: *mut usize) -> u32 {
- *z = 2;
- 99
-}
-
-
-// EMIT_MIR array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir
-fn main() {
- let mut x = [42, 43, 44];
- let mut y = 1;
- let z: *mut usize = &mut y;
- x[y] = unsafe { foo(z) };
-}
// MIR for `main` after SimplifyCfg-elaborate-drops
fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/array-index-is-temporary.rs:+0:11: +0:11
- let mut _1: [u32; 3]; // in scope 0 at $DIR/array-index-is-temporary.rs:+1:9: +1:14
- let mut _4: &mut usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
- let mut _5: u32; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:12: +4:29
- let mut _6: *mut usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:25: +4:26
- let _7: usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:7: +4:8
- let mut _8: usize; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
- let mut _9: bool; // in scope 0 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
+ let mut _0: (); // return place in scope 0 at $DIR/array_index_is_temporary.rs:+0:11: +0:11
+ let mut _1: [u32; 3]; // in scope 0 at $DIR/array_index_is_temporary.rs:+1:9: +1:14
+ let mut _4: &mut usize; // in scope 0 at $DIR/array_index_is_temporary.rs:+3:25: +3:31
+ let mut _5: u32; // in scope 0 at $DIR/array_index_is_temporary.rs:+4:12: +4:29
+ let mut _6: *mut usize; // in scope 0 at $DIR/array_index_is_temporary.rs:+4:25: +4:26
+ let _7: usize; // in scope 0 at $DIR/array_index_is_temporary.rs:+4:7: +4:8
+ let mut _8: usize; // in scope 0 at $DIR/array_index_is_temporary.rs:+4:5: +4:9
+ let mut _9: bool; // in scope 0 at $DIR/array_index_is_temporary.rs:+4:5: +4:9
scope 1 {
- debug x => _1; // in scope 1 at $DIR/array-index-is-temporary.rs:+1:9: +1:14
- let mut _2: usize; // in scope 1 at $DIR/array-index-is-temporary.rs:+2:9: +2:14
+ debug x => _1; // in scope 1 at $DIR/array_index_is_temporary.rs:+1:9: +1:14
+ let mut _2: usize; // in scope 1 at $DIR/array_index_is_temporary.rs:+2:9: +2:14
scope 2 {
- debug y => _2; // in scope 2 at $DIR/array-index-is-temporary.rs:+2:9: +2:14
- let _3: *mut usize; // in scope 2 at $DIR/array-index-is-temporary.rs:+3:9: +3:10
+ debug y => _2; // in scope 2 at $DIR/array_index_is_temporary.rs:+2:9: +2:14
+ let _3: *mut usize; // in scope 2 at $DIR/array_index_is_temporary.rs:+3:9: +3:10
scope 3 {
- debug z => _3; // in scope 3 at $DIR/array-index-is-temporary.rs:+3:9: +3:10
+ debug z => _3; // in scope 3 at $DIR/array_index_is_temporary.rs:+3:9: +3:10
scope 4 {
}
}
}
bb0: {
- StorageLive(_1); // scope 0 at $DIR/array-index-is-temporary.rs:+1:9: +1:14
- _1 = [const 42_u32, const 43_u32, const 44_u32]; // scope 0 at $DIR/array-index-is-temporary.rs:+1:17: +1:29
- StorageLive(_2); // scope 1 at $DIR/array-index-is-temporary.rs:+2:9: +2:14
- _2 = const 1_usize; // scope 1 at $DIR/array-index-is-temporary.rs:+2:17: +2:18
- StorageLive(_3); // scope 2 at $DIR/array-index-is-temporary.rs:+3:9: +3:10
- StorageLive(_4); // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
- _4 = &mut _2; // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
- _3 = &raw mut (*_4); // scope 2 at $DIR/array-index-is-temporary.rs:+3:25: +3:31
- StorageDead(_4); // scope 2 at $DIR/array-index-is-temporary.rs:+3:31: +3:32
- StorageLive(_5); // scope 3 at $DIR/array-index-is-temporary.rs:+4:12: +4:29
- StorageLive(_6); // scope 4 at $DIR/array-index-is-temporary.rs:+4:25: +4:26
- _6 = _3; // scope 4 at $DIR/array-index-is-temporary.rs:+4:25: +4:26
- _5 = foo(move _6) -> bb1; // scope 4 at $DIR/array-index-is-temporary.rs:+4:21: +4:27
+ StorageLive(_1); // scope 0 at $DIR/array_index_is_temporary.rs:+1:9: +1:14
+ _1 = [const 42_u32, const 43_u32, const 44_u32]; // scope 0 at $DIR/array_index_is_temporary.rs:+1:17: +1:29
+ StorageLive(_2); // scope 1 at $DIR/array_index_is_temporary.rs:+2:9: +2:14
+ _2 = const 1_usize; // scope 1 at $DIR/array_index_is_temporary.rs:+2:17: +2:18
+ StorageLive(_3); // scope 2 at $DIR/array_index_is_temporary.rs:+3:9: +3:10
+ StorageLive(_4); // scope 2 at $DIR/array_index_is_temporary.rs:+3:25: +3:31
+ _4 = &mut _2; // scope 2 at $DIR/array_index_is_temporary.rs:+3:25: +3:31
+ _3 = &raw mut (*_4); // scope 2 at $DIR/array_index_is_temporary.rs:+3:25: +3:31
+ StorageDead(_4); // scope 2 at $DIR/array_index_is_temporary.rs:+3:31: +3:32
+ StorageLive(_5); // scope 3 at $DIR/array_index_is_temporary.rs:+4:12: +4:29
+ StorageLive(_6); // scope 4 at $DIR/array_index_is_temporary.rs:+4:25: +4:26
+ _6 = _3; // scope 4 at $DIR/array_index_is_temporary.rs:+4:25: +4:26
+ _5 = foo(move _6) -> bb1; // scope 4 at $DIR/array_index_is_temporary.rs:+4:21: +4:27
// mir::Constant
- // + span: $DIR/array-index-is-temporary.rs:16:21: 16:24
+ // + span: $DIR/array_index_is_temporary.rs:16:21: 16:24
// + literal: Const { ty: unsafe fn(*mut usize) -> u32 {foo}, val: Value(<ZST>) }
}
bb1: {
- StorageDead(_6); // scope 4 at $DIR/array-index-is-temporary.rs:+4:26: +4:27
- StorageLive(_7); // scope 3 at $DIR/array-index-is-temporary.rs:+4:7: +4:8
- _7 = _2; // scope 3 at $DIR/array-index-is-temporary.rs:+4:7: +4:8
- _8 = Len(_1); // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
- _9 = Lt(_7, _8); // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
- assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:9
+ StorageDead(_6); // scope 4 at $DIR/array_index_is_temporary.rs:+4:26: +4:27
+ StorageLive(_7); // scope 3 at $DIR/array_index_is_temporary.rs:+4:7: +4:8
+ _7 = _2; // scope 3 at $DIR/array_index_is_temporary.rs:+4:7: +4:8
+ _8 = Len(_1); // scope 3 at $DIR/array_index_is_temporary.rs:+4:5: +4:9
+ _9 = Lt(_7, _8); // scope 3 at $DIR/array_index_is_temporary.rs:+4:5: +4:9
+ assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 3 at $DIR/array_index_is_temporary.rs:+4:5: +4:9
}
bb2: {
- _1[_7] = move _5; // scope 3 at $DIR/array-index-is-temporary.rs:+4:5: +4:29
- StorageDead(_5); // scope 3 at $DIR/array-index-is-temporary.rs:+4:28: +4:29
- StorageDead(_7); // scope 3 at $DIR/array-index-is-temporary.rs:+4:29: +4:30
- _0 = const (); // scope 0 at $DIR/array-index-is-temporary.rs:+0:11: +5:2
- StorageDead(_3); // scope 2 at $DIR/array-index-is-temporary.rs:+5:1: +5:2
- StorageDead(_2); // scope 1 at $DIR/array-index-is-temporary.rs:+5:1: +5:2
- StorageDead(_1); // scope 0 at $DIR/array-index-is-temporary.rs:+5:1: +5:2
- return; // scope 0 at $DIR/array-index-is-temporary.rs:+5:2: +5:2
+ _1[_7] = move _5; // scope 3 at $DIR/array_index_is_temporary.rs:+4:5: +4:29
+ StorageDead(_5); // scope 3 at $DIR/array_index_is_temporary.rs:+4:28: +4:29
+ StorageDead(_7); // scope 3 at $DIR/array_index_is_temporary.rs:+4:29: +4:30
+ _0 = const (); // scope 0 at $DIR/array_index_is_temporary.rs:+0:11: +5:2
+ StorageDead(_3); // scope 2 at $DIR/array_index_is_temporary.rs:+5:1: +5:2
+ StorageDead(_2); // scope 1 at $DIR/array_index_is_temporary.rs:+5:1: +5:2
+ StorageDead(_1); // scope 0 at $DIR/array_index_is_temporary.rs:+5:1: +5:2
+ return; // scope 0 at $DIR/array_index_is_temporary.rs:+5:2: +5:2
}
}
--- /dev/null
+// Retagging (from Stacked Borrows) relies on the array index being a fresh
+// temporary, so that side-effects cannot change it.
+// Test that this is indeed the case.
+
+unsafe fn foo(z: *mut usize) -> u32 {
+ *z = 2;
+ 99
+}
+
+
+// EMIT_MIR array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir
+fn main() {
+ let mut x = [42, 43, 44];
+ let mut y = 1;
+ let z: *mut usize = &mut y;
+ x[y] = unsafe { foo(z) };
+}
--- /dev/null
+// MIR for `bar` after built
+
+fn bar(_1: Bar) -> usize {
+ debug bar => _1; // in scope 0 at $DIR/enum_cast.rs:+0:8: +0:11
+ let mut _0: usize; // return place in scope 0 at $DIR/enum_cast.rs:+0:21: +0:26
+ let _2: Bar; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
+ let mut _3: isize; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
+ let mut _4: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
+ let mut _5: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
+ _2 = move _1; // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
+ _3 = discriminant(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
+ _4 = Ge(const 1_isize, _3); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
+ assume(_4); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
+ _5 = Le(const 0_isize, _3); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
+ assume(_5); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
+ _0 = move _3 as usize (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
+ StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+1:16: +1:17
+ return; // scope 0 at $DIR/enum_cast.rs:+2:2: +2:2
+ }
+}
--- /dev/null
+// MIR for `boo` after built
+
+fn boo(_1: Boo) -> usize {
+ debug boo => _1; // in scope 0 at $DIR/enum_cast.rs:+0:8: +0:11
+ let mut _0: usize; // return place in scope 0 at $DIR/enum_cast.rs:+0:21: +0:26
+ let _2: Boo; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
+ let mut _3: u8; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
+ let mut _4: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
+ let mut _5: bool; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
+ _2 = move _1; // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
+ _3 = discriminant(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
+ _4 = Ge(const 1_u8, _3); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
+ assume(_4); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
+ _5 = Le(const 0_u8, _3); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
+ assume(_5); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
+ _0 = move _3 as usize (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
+ StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+1:16: +1:17
+ return; // scope 0 at $DIR/enum_cast.rs:+2:2: +2:2
+ }
+}
--- /dev/null
+// MIR for `droppy` after built
+
+fn droppy() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/enum_cast.rs:+0:13: +0:13
+ let _1: (); // in scope 0 at $DIR/enum_cast.rs:+1:5: +6:6
+ let _2: Droppy; // in scope 0 at $DIR/enum_cast.rs:+2:13: +2:14
+ let _4: Droppy; // in scope 0 at $DIR/enum_cast.rs:+5:17: +5:18
+ let mut _5: isize; // in scope 0 at $DIR/enum_cast.rs:+5:17: +5:18
+ let mut _6: bool; // in scope 0 at $DIR/enum_cast.rs:+5:17: +5:27
+ let mut _7: bool; // in scope 0 at $DIR/enum_cast.rs:+5:17: +5:27
+ let _8: Droppy; // in scope 0 at $DIR/enum_cast.rs:+7:9: +7:10
+ scope 1 {
+ debug x => _2; // in scope 1 at $DIR/enum_cast.rs:+2:13: +2:14
+ scope 2 {
+ debug y => _3; // in scope 2 at $DIR/enum_cast.rs:+5:13: +5:14
+ }
+ scope 3 {
+ let _3: usize; // in scope 3 at $DIR/enum_cast.rs:+5:13: +5:14
+ }
+ }
+ scope 4 {
+ debug z => _8; // in scope 4 at $DIR/enum_cast.rs:+7:9: +7:10
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/enum_cast.rs:+1:5: +6:6
+ StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+2:13: +2:14
+ _2 = Droppy::C; // scope 0 at $DIR/enum_cast.rs:+2:17: +2:26
+ FakeRead(ForLet(None), _2); // scope 0 at $DIR/enum_cast.rs:+2:13: +2:14
+ StorageLive(_3); // scope 3 at $DIR/enum_cast.rs:+5:13: +5:14
+ StorageLive(_4); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:18
+ _4 = move _2; // scope 3 at $DIR/enum_cast.rs:+5:17: +5:18
+ _5 = discriminant(_4); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
+ _6 = Ge(const 2_isize, _5); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
+ assume(_6); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
+ _7 = Le(const 0_isize, _5); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
+ assume(_7); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
+ _3 = move _5 as usize (IntToInt); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
+ drop(_4) -> [return: bb1, unwind: bb4]; // scope 3 at $DIR/enum_cast.rs:+5:26: +5:27
+ }
+
+ bb1: {
+ StorageDead(_4); // scope 3 at $DIR/enum_cast.rs:+5:26: +5:27
+ FakeRead(ForLet(None), _3); // scope 3 at $DIR/enum_cast.rs:+5:13: +5:14
+ _1 = const (); // scope 0 at $DIR/enum_cast.rs:+1:5: +6:6
+ StorageDead(_3); // scope 1 at $DIR/enum_cast.rs:+6:5: +6:6
+ drop(_2) -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/enum_cast.rs:+6:5: +6:6
+ }
+
+ bb2: {
+ StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+6:5: +6:6
+ StorageDead(_1); // scope 0 at $DIR/enum_cast.rs:+6:5: +6:6
+ StorageLive(_8); // scope 0 at $DIR/enum_cast.rs:+7:9: +7:10
+ _8 = Droppy::B; // scope 0 at $DIR/enum_cast.rs:+7:13: +7:22
+ FakeRead(ForLet(None), _8); // scope 0 at $DIR/enum_cast.rs:+7:9: +7:10
+ _0 = const (); // scope 0 at $DIR/enum_cast.rs:+0:13: +8:2
+ drop(_8) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/enum_cast.rs:+8:1: +8:2
+ }
+
+ bb3: {
+ StorageDead(_8); // scope 0 at $DIR/enum_cast.rs:+8:1: +8:2
+ return; // scope 0 at $DIR/enum_cast.rs:+8:2: +8:2
+ }
+
+ bb4 (cleanup): {
+ drop(_2) -> bb5; // scope 0 at $DIR/enum_cast.rs:+6:5: +6:6
+ }
+
+ bb5 (cleanup): {
+ resume; // scope 0 at $DIR/enum_cast.rs:+0:1: +8:2
+ }
+}
--- /dev/null
+// MIR for `foo` after built
+
+fn foo(_1: Foo) -> usize {
+ debug foo => _1; // in scope 0 at $DIR/enum_cast.rs:+0:8: +0:11
+ let mut _0: usize; // return place in scope 0 at $DIR/enum_cast.rs:+0:21: +0:26
+ let _2: Foo; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
+ let mut _3: isize; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
+ _2 = move _1; // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
+ _3 = discriminant(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
+ _0 = move _3 as usize (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
+ StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+1:16: +1:17
+ return; // scope 0 at $DIR/enum_cast.rs:+2:2: +2:2
+ }
+}
--- /dev/null
+// EMIT_MIR enum_cast.foo.built.after.mir
+// EMIT_MIR enum_cast.bar.built.after.mir
+// EMIT_MIR enum_cast.boo.built.after.mir
+
+enum Foo {
+ A
+}
+
+enum Bar {
+ A, B
+}
+
+#[repr(u8)]
+enum Boo {
+ A, B
+}
+
+fn foo(foo: Foo) -> usize {
+ foo as usize
+}
+
+fn bar(bar: Bar) -> usize {
+ bar as usize
+}
+
+fn boo(boo: Boo) -> usize {
+ boo as usize
+}
+
+// EMIT_MIR enum_cast.droppy.built.after.mir
+enum Droppy {
+ A, B, C
+}
+
+impl Drop for Droppy {
+ fn drop(&mut self) {}
+}
+
+fn droppy() {
+ {
+ let x = Droppy::C;
+ // remove this entire test once `cenum_impl_drop_cast` becomes a hard error
+ #[allow(cenum_impl_drop_cast)]
+ let y = x as usize;
+ }
+ let z = Droppy::B;
+}
+
+fn main() {
+}
--- /dev/null
+// MIR for `main` after built
+
+| User Type Annotations
+| 0: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(std::option::Option<u8>) }, span: $DIR/issue_101867.rs:3:12: 3:22, inferred_ty: std::option::Option<u8>
+| 1: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(std::option::Option<u8>) }, span: $DIR/issue_101867.rs:3:12: 3:22, inferred_ty: std::option::Option<u8>
+|
+fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/issue_101867.rs:+0:11: +0:11
+ let _1: std::option::Option<u8> as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/issue_101867.rs:+1:9: +1:10
+ let mut _2: !; // in scope 0 at $DIR/issue_101867.rs:+2:26: +4:6
+ let _3: (); // in scope 0 at $SRC_DIR/std/src/panic.rs:LL:COL
+ let mut _4: !; // in scope 0 at $SRC_DIR/std/src/panic.rs:LL:COL
+ let mut _6: isize; // in scope 0 at $DIR/issue_101867.rs:+2:9: +2:16
+ scope 1 {
+ debug x => _1; // in scope 1 at $DIR/issue_101867.rs:+1:9: +1:10
+ let _5: u8; // in scope 1 at $DIR/issue_101867.rs:+2:14: +2:15
+ scope 2 {
+ debug y => _5; // in scope 2 at $DIR/issue_101867.rs:+2:14: +2:15
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/issue_101867.rs:+1:9: +1:10
+ _1 = Option::<u8>::Some(const 1_u8); // scope 0 at $DIR/issue_101867.rs:+1:25: +1:32
+ FakeRead(ForLet(None), _1); // scope 0 at $DIR/issue_101867.rs:+1:9: +1:10
+ AscribeUserType(_1, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 0 at $DIR/issue_101867.rs:+1:12: +1:22
+ StorageLive(_5); // scope 1 at $DIR/issue_101867.rs:+2:14: +2:15
+ FakeRead(ForMatchedPlace(None), _1); // scope 1 at $DIR/issue_101867.rs:+2:19: +2:20
+ _6 = discriminant(_1); // scope 1 at $DIR/issue_101867.rs:+2:19: +2:20
+ switchInt(move _6) -> [1_isize: bb4, otherwise: bb3]; // scope 1 at $DIR/issue_101867.rs:+2:9: +2:16
+ }
+
+ bb1: {
+ StorageLive(_3); // scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL
+ StorageLive(_4); // scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL
+ _4 = begin_panic::<&str>(const "explicit panic") -> bb7; // scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL
+ // mir::Constant
+ // + span: $SRC_DIR/std/src/panic.rs:LL:COL
+ // + literal: Const { ty: fn(&str) -> ! {begin_panic::<&str>}, val: Value(<ZST>) }
+ // mir::Constant
+ // + span: $SRC_DIR/std/src/panic.rs:LL:COL
+ // + literal: Const { ty: &str, val: Value(Slice(..)) }
+ }
+
+ bb2: {
+ StorageDead(_4); // scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL
+ StorageDead(_3); // scope 1 at $DIR/issue_101867.rs:+3:16: +3:17
+ unreachable; // scope 1 at $DIR/issue_101867.rs:+2:26: +4:6
+ }
+
+ bb3: {
+ goto -> bb6; // scope 1 at $DIR/issue_101867.rs:+2:19: +2:20
+ }
+
+ bb4: {
+ falseEdge -> [real: bb5, imaginary: bb3]; // scope 1 at $DIR/issue_101867.rs:+2:9: +2:16
+ }
+
+ bb5: {
+ _5 = ((_1 as Some).0: u8); // scope 1 at $DIR/issue_101867.rs:+2:14: +2:15
+ _0 = const (); // scope 0 at $DIR/issue_101867.rs:+0:11: +5:2
+ StorageDead(_5); // scope 1 at $DIR/issue_101867.rs:+5:1: +5:2
+ StorageDead(_1); // scope 0 at $DIR/issue_101867.rs:+5:1: +5:2
+ return; // scope 0 at $DIR/issue_101867.rs:+5:2: +5:2
+ }
+
+ bb6: {
+ StorageDead(_5); // scope 1 at $DIR/issue_101867.rs:+5:1: +5:2
+ goto -> bb1; // scope 0 at $DIR/issue_101867.rs:+0:11: +5:2
+ }
+
+ bb7 (cleanup): {
+ resume; // scope 0 at $DIR/issue_101867.rs:+0:1: +5:2
+ }
+}
--- /dev/null
+// EMIT_MIR issue_101867.main.built.after.mir
+fn main() {
+ let x: Option<u8> = Some(1);
+ let Some(y) = x else {
+ panic!();
+ };
+}
--- /dev/null
+// MIR for `main` after built
+
+fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/issue_49232.rs:+0:11: +0:11
+ let mut _1: (); // in scope 0 at $DIR/issue_49232.rs:+0:1: +10:2
+ let _2: i32; // in scope 0 at $DIR/issue_49232.rs:+2:13: +2:19
+ let mut _3: bool; // in scope 0 at $DIR/issue_49232.rs:+3:19: +3:23
+ let mut _4: !; // in scope 0 at $DIR/issue_49232.rs:+5:25: +5:30
+ let _5: (); // in scope 0 at $DIR/issue_49232.rs:+8:9: +8:22
+ let mut _6: &i32; // in scope 0 at $DIR/issue_49232.rs:+8:14: +8:21
+ scope 1 {
+ debug beacon => _2; // in scope 1 at $DIR/issue_49232.rs:+2:13: +2:19
+ }
+
+ bb0: {
+ goto -> bb1; // scope 0 at $DIR/issue_49232.rs:+1:5: +9:6
+ }
+
+ bb1: {
+ falseUnwind -> [real: bb2, cleanup: bb11]; // scope 0 at $DIR/issue_49232.rs:+1:5: +9:6
+ }
+
+ bb2: {
+ StorageLive(_2); // scope 0 at $DIR/issue_49232.rs:+2:13: +2:19
+ StorageLive(_3); // scope 0 at $DIR/issue_49232.rs:+3:19: +3:23
+ _3 = const true; // scope 0 at $DIR/issue_49232.rs:+3:19: +3:23
+ FakeRead(ForMatchedPlace(None), _3); // scope 0 at $DIR/issue_49232.rs:+3:19: +3:23
+ switchInt(_3) -> [false: bb3, otherwise: bb4]; // scope 0 at $DIR/issue_49232.rs:+3:13: +3:23
+ }
+
+ bb3: {
+ falseEdge -> [real: bb5, imaginary: bb4]; // scope 0 at $DIR/issue_49232.rs:+4:17: +4:22
+ }
+
+ bb4: {
+ _0 = const (); // scope 0 at $DIR/issue_49232.rs:+5:25: +5:30
+ goto -> bb10; // scope 0 at $DIR/issue_49232.rs:+5:25: +5:30
+ }
+
+ bb5: {
+ _2 = const 4_i32; // scope 0 at $DIR/issue_49232.rs:+4:26: +4:27
+ goto -> bb8; // scope 0 at $DIR/issue_49232.rs:+4:26: +4:27
+ }
+
+ bb6: {
+ unreachable; // scope 0 at $DIR/issue_49232.rs:+5:25: +5:30
+ }
+
+ bb7: {
+ goto -> bb8; // scope 0 at $DIR/issue_49232.rs:+6:13: +6:14
+ }
+
+ bb8: {
+ FakeRead(ForLet(None), _2); // scope 0 at $DIR/issue_49232.rs:+2:13: +2:19
+ StorageDead(_3); // scope 0 at $DIR/issue_49232.rs:+7:10: +7:11
+ StorageLive(_5); // scope 1 at $DIR/issue_49232.rs:+8:9: +8:22
+ StorageLive(_6); // scope 1 at $DIR/issue_49232.rs:+8:14: +8:21
+ _6 = &_2; // scope 1 at $DIR/issue_49232.rs:+8:14: +8:21
+ _5 = std::mem::drop::<&i32>(move _6) -> [return: bb9, unwind: bb11]; // scope 1 at $DIR/issue_49232.rs:+8:9: +8:22
+ // mir::Constant
+ // + span: $DIR/issue_49232.rs:13:9: 13:13
+ // + literal: Const { ty: fn(&i32) {std::mem::drop::<&i32>}, val: Value(<ZST>) }
+ }
+
+ bb9: {
+ StorageDead(_6); // scope 1 at $DIR/issue_49232.rs:+8:21: +8:22
+ StorageDead(_5); // scope 1 at $DIR/issue_49232.rs:+8:22: +8:23
+ _1 = const (); // scope 0 at $DIR/issue_49232.rs:+1:10: +9:6
+ StorageDead(_2); // scope 0 at $DIR/issue_49232.rs:+9:5: +9:6
+ goto -> bb1; // scope 0 at $DIR/issue_49232.rs:+1:5: +9:6
+ }
+
+ bb10: {
+ StorageDead(_3); // scope 0 at $DIR/issue_49232.rs:+7:10: +7:11
+ StorageDead(_2); // scope 0 at $DIR/issue_49232.rs:+9:5: +9:6
+ return; // scope 0 at $DIR/issue_49232.rs:+10:2: +10:2
+ }
+
+ bb11 (cleanup): {
+ resume; // scope 0 at $DIR/issue_49232.rs:+0:1: +10:2
+ }
+}
--- /dev/null
+// We must mark a variable whose initialization fails due to an
+// abort statement as StorageDead.
+
+// EMIT_MIR issue_49232.main.built.after.mir
+fn main() {
+ loop {
+ let beacon = {
+ match true {
+ false => 4,
+ true => break,
+ }
+ };
+ drop(&beacon);
+ }
+}
--- /dev/null
+// MIR for `full_tested_match` after built
+
+fn full_tested_match() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/match_false_edges.rs:+0:28: +0:28
+ let mut _1: (i32, i32); // in scope 0 at $DIR/match_false_edges.rs:+1:13: +5:6
+ let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
+ let mut _3: isize; // in scope 0 at $DIR/match_false_edges.rs:+2:9: +2:16
+ let mut _4: &std::option::Option<i32>; // in scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
+ let _5: i32; // in scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15
+ let _6: &i32; // in scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15
+ let mut _7: bool; // in scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27
+ let mut _8: i32; // in scope 0 at $DIR/match_false_edges.rs:+2:35: +2:36
+ let _9: i32; // in scope 0 at $DIR/match_false_edges.rs:+3:14: +3:15
+ let mut _10: i32; // in scope 0 at $DIR/match_false_edges.rs:+3:24: +3:25
+ scope 1 {
+ }
+ scope 2 {
+ debug x => _5; // in scope 2 at $DIR/match_false_edges.rs:+2:14: +2:15
+ debug x => _6; // in scope 2 at $DIR/match_false_edges.rs:+2:14: +2:15
+ }
+ scope 3 {
+ debug y => _9; // in scope 3 at $DIR/match_false_edges.rs:+3:14: +3:15
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:+1:13: +5:6
+ StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
+ _2 = Option::<i32>::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
+ FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
+ _3 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
+ switchInt(move _3) -> [0_isize: bb1, 1_isize: bb2, otherwise: bb4]; // scope 0 at $DIR/match_false_edges.rs:+1:13: +1:27
+ }
+
+ bb1: {
+ _1 = (const 3_i32, const 3_i32); // scope 0 at $DIR/match_false_edges.rs:+4:17: +4:23
+ goto -> bb11; // scope 0 at $DIR/match_false_edges.rs:+4:17: +4:23
+ }
+
+ bb2: {
+ falseEdge -> [real: bb5, imaginary: bb3]; // scope 0 at $DIR/match_false_edges.rs:+2:9: +2:16
+ }
+
+ bb3: {
+ falseEdge -> [real: bb10, imaginary: bb1]; // scope 0 at $DIR/match_false_edges.rs:+3:9: +3:16
+ }
+
+ bb4: {
+ unreachable; // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
+ }
+
+ bb5: {
+ StorageLive(_6); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15
+ _6 = &((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15
+ _4 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
+ StorageLive(_7); // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27
+ _7 = guard() -> [return: bb6, unwind: bb12]; // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27
+ // mir::Constant
+ // + span: $DIR/match_false_edges.rs:14:20: 14:25
+ // + literal: Const { ty: fn() -> bool {guard}, val: Value(<ZST>) }
+ }
+
+ bb6: {
+ switchInt(move _7) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27
+ }
+
+ bb7: {
+ StorageDead(_7); // scope 0 at $DIR/match_false_edges.rs:+2:26: +2:27
+ FakeRead(ForMatchGuard, _4); // scope 0 at $DIR/match_false_edges.rs:+2:26: +2:27
+ FakeRead(ForGuardBinding, _6); // scope 0 at $DIR/match_false_edges.rs:+2:26: +2:27
+ StorageLive(_5); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15
+ _5 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15
+ StorageLive(_8); // scope 2 at $DIR/match_false_edges.rs:+2:35: +2:36
+ _8 = _5; // scope 2 at $DIR/match_false_edges.rs:+2:35: +2:36
+ _1 = (const 1_i32, move _8); // scope 2 at $DIR/match_false_edges.rs:+2:31: +2:37
+ StorageDead(_8); // scope 2 at $DIR/match_false_edges.rs:+2:36: +2:37
+ StorageDead(_5); // scope 0 at $DIR/match_false_edges.rs:+2:36: +2:37
+ StorageDead(_6); // scope 0 at $DIR/match_false_edges.rs:+2:36: +2:37
+ goto -> bb11; // scope 0 at $DIR/match_false_edges.rs:+2:36: +2:37
+ }
+
+ bb8: {
+ goto -> bb9; // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27
+ }
+
+ bb9: {
+ StorageDead(_7); // scope 0 at $DIR/match_false_edges.rs:+2:26: +2:27
+ StorageDead(_6); // scope 0 at $DIR/match_false_edges.rs:+2:36: +2:37
+ goto -> bb3; // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27
+ }
+
+ bb10: {
+ StorageLive(_9); // scope 0 at $DIR/match_false_edges.rs:+3:14: +3:15
+ _9 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+3:14: +3:15
+ StorageLive(_10); // scope 3 at $DIR/match_false_edges.rs:+3:24: +3:25
+ _10 = _9; // scope 3 at $DIR/match_false_edges.rs:+3:24: +3:25
+ _1 = (const 2_i32, move _10); // scope 3 at $DIR/match_false_edges.rs:+3:20: +3:26
+ StorageDead(_10); // scope 3 at $DIR/match_false_edges.rs:+3:25: +3:26
+ StorageDead(_9); // scope 0 at $DIR/match_false_edges.rs:+3:25: +3:26
+ goto -> bb11; // scope 0 at $DIR/match_false_edges.rs:+3:25: +3:26
+ }
+
+ bb11: {
+ StorageDead(_2); // scope 0 at $DIR/match_false_edges.rs:+5:6: +5:7
+ StorageDead(_1); // scope 0 at $DIR/match_false_edges.rs:+5:6: +5:7
+ _0 = const (); // scope 0 at $DIR/match_false_edges.rs:+0:28: +6:2
+ return; // scope 0 at $DIR/match_false_edges.rs:+6:2: +6:2
+ }
+
+ bb12 (cleanup): {
+ resume; // scope 0 at $DIR/match_false_edges.rs:+0:1: +6:2
+ }
+}
--- /dev/null
+// MIR for `full_tested_match2` after built
+
+fn full_tested_match2() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/match_false_edges.rs:+0:29: +0:29
+ let mut _1: (i32, i32); // in scope 0 at $DIR/match_false_edges.rs:+1:13: +5:6
+ let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
+ let mut _3: isize; // in scope 0 at $DIR/match_false_edges.rs:+2:9: +2:16
+ let mut _4: &std::option::Option<i32>; // in scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
+ let _5: i32; // in scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15
+ let _6: &i32; // in scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15
+ let mut _7: bool; // in scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27
+ let mut _8: i32; // in scope 0 at $DIR/match_false_edges.rs:+2:35: +2:36
+ let _9: i32; // in scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15
+ let mut _10: i32; // in scope 0 at $DIR/match_false_edges.rs:+4:24: +4:25
+ scope 1 {
+ }
+ scope 2 {
+ debug x => _5; // in scope 2 at $DIR/match_false_edges.rs:+2:14: +2:15
+ debug x => _6; // in scope 2 at $DIR/match_false_edges.rs:+2:14: +2:15
+ }
+ scope 3 {
+ debug y => _9; // in scope 3 at $DIR/match_false_edges.rs:+4:14: +4:15
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:+1:13: +5:6
+ StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
+ _2 = Option::<i32>::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
+ FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
+ _3 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
+ switchInt(move _3) -> [0_isize: bb1, 1_isize: bb2, otherwise: bb4]; // scope 0 at $DIR/match_false_edges.rs:+1:13: +1:27
+ }
+
+ bb1: {
+ falseEdge -> [real: bb10, imaginary: bb3]; // scope 0 at $DIR/match_false_edges.rs:+3:9: +3:13
+ }
+
+ bb2: {
+ falseEdge -> [real: bb5, imaginary: bb1]; // scope 0 at $DIR/match_false_edges.rs:+2:9: +2:16
+ }
+
+ bb3: {
+ StorageLive(_9); // scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15
+ _9 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15
+ StorageLive(_10); // scope 3 at $DIR/match_false_edges.rs:+4:24: +4:25
+ _10 = _9; // scope 3 at $DIR/match_false_edges.rs:+4:24: +4:25
+ _1 = (const 2_i32, move _10); // scope 3 at $DIR/match_false_edges.rs:+4:20: +4:26
+ StorageDead(_10); // scope 3 at $DIR/match_false_edges.rs:+4:25: +4:26
+ StorageDead(_9); // scope 0 at $DIR/match_false_edges.rs:+4:25: +4:26
+ goto -> bb11; // scope 0 at $DIR/match_false_edges.rs:+4:25: +4:26
+ }
+
+ bb4: {
+ unreachable; // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
+ }
+
+ bb5: {
+ StorageLive(_6); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15
+ _6 = &((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15
+ _4 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
+ StorageLive(_7); // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27
+ _7 = guard() -> [return: bb6, unwind: bb12]; // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27
+ // mir::Constant
+ // + span: $DIR/match_false_edges.rs:25:20: 25:25
+ // + literal: Const { ty: fn() -> bool {guard}, val: Value(<ZST>) }
+ }
+
+ bb6: {
+ switchInt(move _7) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27
+ }
+
+ bb7: {
+ StorageDead(_7); // scope 0 at $DIR/match_false_edges.rs:+2:26: +2:27
+ FakeRead(ForMatchGuard, _4); // scope 0 at $DIR/match_false_edges.rs:+2:26: +2:27
+ FakeRead(ForGuardBinding, _6); // scope 0 at $DIR/match_false_edges.rs:+2:26: +2:27
+ StorageLive(_5); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15
+ _5 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15
+ StorageLive(_8); // scope 2 at $DIR/match_false_edges.rs:+2:35: +2:36
+ _8 = _5; // scope 2 at $DIR/match_false_edges.rs:+2:35: +2:36
+ _1 = (const 1_i32, move _8); // scope 2 at $DIR/match_false_edges.rs:+2:31: +2:37
+ StorageDead(_8); // scope 2 at $DIR/match_false_edges.rs:+2:36: +2:37
+ StorageDead(_5); // scope 0 at $DIR/match_false_edges.rs:+2:36: +2:37
+ StorageDead(_6); // scope 0 at $DIR/match_false_edges.rs:+2:36: +2:37
+ goto -> bb11; // scope 0 at $DIR/match_false_edges.rs:+2:36: +2:37
+ }
+
+ bb8: {
+ goto -> bb9; // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27
+ }
+
+ bb9: {
+ StorageDead(_7); // scope 0 at $DIR/match_false_edges.rs:+2:26: +2:27
+ StorageDead(_6); // scope 0 at $DIR/match_false_edges.rs:+2:36: +2:37
+ falseEdge -> [real: bb3, imaginary: bb1]; // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27
+ }
+
+ bb10: {
+ _1 = (const 3_i32, const 3_i32); // scope 0 at $DIR/match_false_edges.rs:+3:17: +3:23
+ goto -> bb11; // scope 0 at $DIR/match_false_edges.rs:+3:17: +3:23
+ }
+
+ bb11: {
+ StorageDead(_2); // scope 0 at $DIR/match_false_edges.rs:+5:6: +5:7
+ StorageDead(_1); // scope 0 at $DIR/match_false_edges.rs:+5:6: +5:7
+ _0 = const (); // scope 0 at $DIR/match_false_edges.rs:+0:29: +6:2
+ return; // scope 0 at $DIR/match_false_edges.rs:+6:2: +6:2
+ }
+
+ bb12 (cleanup): {
+ resume; // scope 0 at $DIR/match_false_edges.rs:+0:1: +6:2
+ }
+}
--- /dev/null
+// MIR for `main` after built
+
+fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/match_false_edges.rs:+0:11: +0:11
+ let mut _1: i32; // in scope 0 at $DIR/match_false_edges.rs:+1:13: +6:6
+ let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26
+ let mut _3: isize; // in scope 0 at $DIR/match_false_edges.rs:+4:9: +4:16
+ let mut _4: isize; // in scope 0 at $DIR/match_false_edges.rs:+2:9: +2:17
+ let mut _5: &std::option::Option<i32>; // in scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26
+ let _6: i32; // in scope 0 at $DIR/match_false_edges.rs:+2:14: +2:16
+ let _7: &i32; // in scope 0 at $DIR/match_false_edges.rs:+2:14: +2:16
+ let mut _8: bool; // in scope 0 at $DIR/match_false_edges.rs:+2:21: +2:28
+ let _9: std::option::Option<i32>; // in scope 0 at $DIR/match_false_edges.rs:+3:9: +3:11
+ let _10: i32; // in scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15
+ let _11: &i32; // in scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15
+ let mut _12: bool; // in scope 0 at $DIR/match_false_edges.rs:+4:20: +4:29
+ let mut _13: i32; // in scope 0 at $DIR/match_false_edges.rs:+4:27: +4:28
+ let _14: std::option::Option<i32>; // in scope 0 at $DIR/match_false_edges.rs:+5:9: +5:11
+ scope 1 {
+ }
+ scope 2 {
+ debug _w => _6; // in scope 2 at $DIR/match_false_edges.rs:+2:14: +2:16
+ debug _w => _7; // in scope 2 at $DIR/match_false_edges.rs:+2:14: +2:16
+ }
+ scope 3 {
+ debug _x => _9; // in scope 3 at $DIR/match_false_edges.rs:+3:9: +3:11
+ }
+ scope 4 {
+ debug y => _10; // in scope 4 at $DIR/match_false_edges.rs:+4:14: +4:15
+ debug y => _11; // in scope 4 at $DIR/match_false_edges.rs:+4:14: +4:15
+ }
+ scope 5 {
+ debug _z => _14; // in scope 5 at $DIR/match_false_edges.rs:+5:9: +5:11
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:+1:13: +6:6
+ StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26
+ _2 = Option::<i32>::Some(const 1_i32); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26
+ FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26
+ _4 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26
+ switchInt(move _4) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/match_false_edges.rs:+1:13: +1:26
+ }
+
+ bb1: {
+ falseEdge -> [real: bb13, imaginary: bb6]; // scope 0 at $DIR/match_false_edges.rs:+3:9: +3:11
+ }
+
+ bb2: {
+ falseEdge -> [real: bb8, imaginary: bb1]; // scope 0 at $DIR/match_false_edges.rs:+2:9: +2:17
+ }
+
+ bb3: {
+ goto -> bb1; // scope 0 at $DIR/match_false_edges.rs:+1:13: +1:26
+ }
+
+ bb4: {
+ _3 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26
+ switchInt(move _3) -> [1_isize: bb6, otherwise: bb5]; // scope 0 at $DIR/match_false_edges.rs:+1:13: +1:26
+ }
+
+ bb5: {
+ StorageLive(_14); // scope 0 at $DIR/match_false_edges.rs:+5:9: +5:11
+ _14 = _2; // scope 0 at $DIR/match_false_edges.rs:+5:9: +5:11
+ _1 = const 4_i32; // scope 5 at $DIR/match_false_edges.rs:+5:15: +5:16
+ StorageDead(_14); // scope 0 at $DIR/match_false_edges.rs:+5:15: +5:16
+ goto -> bb19; // scope 0 at $DIR/match_false_edges.rs:+5:15: +5:16
+ }
+
+ bb6: {
+ falseEdge -> [real: bb14, imaginary: bb5]; // scope 0 at $DIR/match_false_edges.rs:+4:9: +4:16
+ }
+
+ bb7: {
+ goto -> bb5; // scope 0 at $DIR/match_false_edges.rs:+1:13: +1:26
+ }
+
+ bb8: {
+ StorageLive(_7); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:16
+ _7 = &((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:16
+ _5 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26
+ StorageLive(_8); // scope 0 at $DIR/match_false_edges.rs:+2:21: +2:28
+ _8 = guard() -> [return: bb9, unwind: bb20]; // scope 0 at $DIR/match_false_edges.rs:+2:21: +2:28
+ // mir::Constant
+ // + span: $DIR/match_false_edges.rs:34:21: 34:26
+ // + literal: Const { ty: fn() -> bool {guard}, val: Value(<ZST>) }
+ }
+
+ bb9: {
+ switchInt(move _8) -> [false: bb11, otherwise: bb10]; // scope 0 at $DIR/match_false_edges.rs:+2:21: +2:28
+ }
+
+ bb10: {
+ StorageDead(_8); // scope 0 at $DIR/match_false_edges.rs:+2:27: +2:28
+ FakeRead(ForMatchGuard, _5); // scope 0 at $DIR/match_false_edges.rs:+2:27: +2:28
+ FakeRead(ForGuardBinding, _7); // scope 0 at $DIR/match_false_edges.rs:+2:27: +2:28
+ StorageLive(_6); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:16
+ _6 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:16
+ _1 = const 1_i32; // scope 2 at $DIR/match_false_edges.rs:+2:32: +2:33
+ StorageDead(_6); // scope 0 at $DIR/match_false_edges.rs:+2:32: +2:33
+ StorageDead(_7); // scope 0 at $DIR/match_false_edges.rs:+2:32: +2:33
+ goto -> bb19; // scope 0 at $DIR/match_false_edges.rs:+2:32: +2:33
+ }
+
+ bb11: {
+ goto -> bb12; // scope 0 at $DIR/match_false_edges.rs:+2:21: +2:28
+ }
+
+ bb12: {
+ StorageDead(_8); // scope 0 at $DIR/match_false_edges.rs:+2:27: +2:28
+ StorageDead(_7); // scope 0 at $DIR/match_false_edges.rs:+2:32: +2:33
+ falseEdge -> [real: bb3, imaginary: bb1]; // scope 0 at $DIR/match_false_edges.rs:+2:21: +2:28
+ }
+
+ bb13: {
+ StorageLive(_9); // scope 0 at $DIR/match_false_edges.rs:+3:9: +3:11
+ _9 = _2; // scope 0 at $DIR/match_false_edges.rs:+3:9: +3:11
+ _1 = const 2_i32; // scope 3 at $DIR/match_false_edges.rs:+3:15: +3:16
+ StorageDead(_9); // scope 0 at $DIR/match_false_edges.rs:+3:15: +3:16
+ goto -> bb19; // scope 0 at $DIR/match_false_edges.rs:+3:15: +3:16
+ }
+
+ bb14: {
+ StorageLive(_11); // scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15
+ _11 = &((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15
+ _5 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26
+ StorageLive(_12); // scope 0 at $DIR/match_false_edges.rs:+4:20: +4:29
+ StorageLive(_13); // scope 0 at $DIR/match_false_edges.rs:+4:27: +4:28
+ _13 = (*_11); // scope 0 at $DIR/match_false_edges.rs:+4:27: +4:28
+ _12 = guard2(move _13) -> [return: bb15, unwind: bb20]; // scope 0 at $DIR/match_false_edges.rs:+4:20: +4:29
+ // mir::Constant
+ // + span: $DIR/match_false_edges.rs:36:20: 36:26
+ // + literal: Const { ty: fn(i32) -> bool {guard2}, val: Value(<ZST>) }
+ }
+
+ bb15: {
+ switchInt(move _12) -> [false: bb17, otherwise: bb16]; // scope 0 at $DIR/match_false_edges.rs:+4:20: +4:29
+ }
+
+ bb16: {
+ StorageDead(_13); // scope 0 at $DIR/match_false_edges.rs:+4:28: +4:29
+ StorageDead(_12); // scope 0 at $DIR/match_false_edges.rs:+4:28: +4:29
+ FakeRead(ForMatchGuard, _5); // scope 0 at $DIR/match_false_edges.rs:+4:28: +4:29
+ FakeRead(ForGuardBinding, _11); // scope 0 at $DIR/match_false_edges.rs:+4:28: +4:29
+ StorageLive(_10); // scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15
+ _10 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15
+ _1 = const 3_i32; // scope 4 at $DIR/match_false_edges.rs:+4:33: +4:34
+ StorageDead(_10); // scope 0 at $DIR/match_false_edges.rs:+4:33: +4:34
+ StorageDead(_11); // scope 0 at $DIR/match_false_edges.rs:+4:33: +4:34
+ goto -> bb19; // scope 0 at $DIR/match_false_edges.rs:+4:33: +4:34
+ }
+
+ bb17: {
+ goto -> bb18; // scope 0 at $DIR/match_false_edges.rs:+4:20: +4:29
+ }
+
+ bb18: {
+ StorageDead(_13); // scope 0 at $DIR/match_false_edges.rs:+4:28: +4:29
+ StorageDead(_12); // scope 0 at $DIR/match_false_edges.rs:+4:28: +4:29
+ StorageDead(_11); // scope 0 at $DIR/match_false_edges.rs:+4:33: +4:34
+ falseEdge -> [real: bb7, imaginary: bb5]; // scope 0 at $DIR/match_false_edges.rs:+4:20: +4:29
+ }
+
+ bb19: {
+ StorageDead(_2); // scope 0 at $DIR/match_false_edges.rs:+6:6: +6:7
+ StorageDead(_1); // scope 0 at $DIR/match_false_edges.rs:+6:6: +6:7
+ _0 = const (); // scope 0 at $DIR/match_false_edges.rs:+0:11: +7:2
+ return; // scope 0 at $DIR/match_false_edges.rs:+7:2: +7:2
+ }
+
+ bb20 (cleanup): {
+ resume; // scope 0 at $DIR/match_false_edges.rs:+0:1: +7:2
+ }
+}
--- /dev/null
+fn guard() -> bool {
+ false
+}
+
+fn guard2(_: i32) -> bool {
+ true
+}
+
+// no_mangle to make sure this gets instantiated even in an executable.
+#[no_mangle]
+// EMIT_MIR match_false_edges.full_tested_match.built.after.mir
+pub fn full_tested_match() {
+ let _ = match Some(42) {
+ Some(x) if guard() => (1, x),
+ Some(y) => (2, y),
+ None => (3, 3),
+ };
+}
+
+// no_mangle to make sure this gets instantiated even in an executable.
+#[no_mangle]
+// EMIT_MIR match_false_edges.full_tested_match2.built.after.mir
+pub fn full_tested_match2() {
+ let _ = match Some(42) {
+ Some(x) if guard() => (1, x),
+ None => (3, 3),
+ Some(y) => (2, y),
+ };
+}
+
+// EMIT_MIR match_false_edges.main.built.after.mir
+fn main() {
+ let _ = match Some(1) {
+ Some(_w) if guard() => 1,
+ _x => 2,
+ Some(y) if guard2(y) => 3,
+ _z => 4,
+ };
+}
--- /dev/null
+// MIR for `main` after built
+
+| User Type Annotations
+| 0: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*mut Test) }, span: $DIR/receiver_ptr_mutability.rs:14:14: 14:23, inferred_ty: *mut Test
+| 1: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*mut Test) }, span: $DIR/receiver_ptr_mutability.rs:14:14: 14:23, inferred_ty: *mut Test
+| 2: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }], value: Ty(&&&&*mut Test) }, span: $DIR/receiver_ptr_mutability.rs:18:18: 18:31, inferred_ty: &&&&*mut Test
+| 3: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }], value: Ty(&&&&*mut Test) }, span: $DIR/receiver_ptr_mutability.rs:18:18: 18:31, inferred_ty: &&&&*mut Test
+|
+fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/receiver_ptr_mutability.rs:+0:11: +0:11
+ let _1: *mut Test as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/receiver_ptr_mutability.rs:+1:9: +1:12
+ let _2: (); // in scope 0 at $DIR/receiver_ptr_mutability.rs:+2:5: +2:12
+ let mut _3: *const Test; // in scope 0 at $DIR/receiver_ptr_mutability.rs:+2:5: +2:12
+ let mut _4: *mut Test; // in scope 0 at $DIR/receiver_ptr_mutability.rs:+2:5: +2:8
+ let _6: &&&&*mut Test; // in scope 0 at $DIR/receiver_ptr_mutability.rs:+5:34: +5:41
+ let _7: &&&*mut Test; // in scope 0 at $DIR/receiver_ptr_mutability.rs:+5:35: +5:41
+ let _8: &&*mut Test; // in scope 0 at $DIR/receiver_ptr_mutability.rs:+5:36: +5:41
+ let _9: &*mut Test; // in scope 0 at $DIR/receiver_ptr_mutability.rs:+5:37: +5:41
+ let _10: (); // in scope 0 at $DIR/receiver_ptr_mutability.rs:+6:5: +6:16
+ let mut _11: *const Test; // in scope 0 at $DIR/receiver_ptr_mutability.rs:+6:5: +6:16
+ let mut _12: *mut Test; // in scope 0 at $DIR/receiver_ptr_mutability.rs:+6:5: +6:16
+ scope 1 {
+ debug ptr => _1; // in scope 1 at $DIR/receiver_ptr_mutability.rs:+1:9: +1:12
+ let _5: &&&&*mut Test as UserTypeProjection { base: UserType(2), projs: [] }; // in scope 1 at $DIR/receiver_ptr_mutability.rs:+5:9: +5:16
+ scope 2 {
+ debug ptr_ref => _5; // in scope 2 at $DIR/receiver_ptr_mutability.rs:+5:9: +5:16
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/receiver_ptr_mutability.rs:+1:9: +1:12
+ _1 = null_mut::<Test>() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/receiver_ptr_mutability.rs:+1:26: +1:46
+ // mir::Constant
+ // + span: $DIR/receiver_ptr_mutability.rs:14:26: 14:44
+ // + literal: Const { ty: fn() -> *mut Test {null_mut::<Test>}, val: Value(<ZST>) }
+ }
+
+ bb1: {
+ FakeRead(ForLet(None), _1); // scope 0 at $DIR/receiver_ptr_mutability.rs:+1:9: +1:12
+ AscribeUserType(_1, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 0 at $DIR/receiver_ptr_mutability.rs:+1:14: +1:23
+ StorageLive(_2); // scope 1 at $DIR/receiver_ptr_mutability.rs:+2:5: +2:12
+ StorageLive(_3); // scope 1 at $DIR/receiver_ptr_mutability.rs:+2:5: +2:12
+ StorageLive(_4); // scope 1 at $DIR/receiver_ptr_mutability.rs:+2:5: +2:8
+ _4 = _1; // scope 1 at $DIR/receiver_ptr_mutability.rs:+2:5: +2:8
+ _3 = move _4 as *const Test (Pointer(MutToConstPointer)); // scope 1 at $DIR/receiver_ptr_mutability.rs:+2:5: +2:12
+ StorageDead(_4); // scope 1 at $DIR/receiver_ptr_mutability.rs:+2:7: +2:8
+ _2 = Test::x(move _3) -> [return: bb2, unwind: bb4]; // scope 1 at $DIR/receiver_ptr_mutability.rs:+2:5: +2:12
+ // mir::Constant
+ // + span: $DIR/receiver_ptr_mutability.rs:15:9: 15:10
+ // + literal: Const { ty: fn(*const Test) {Test::x}, val: Value(<ZST>) }
+ }
+
+ bb2: {
+ StorageDead(_3); // scope 1 at $DIR/receiver_ptr_mutability.rs:+2:11: +2:12
+ StorageDead(_2); // scope 1 at $DIR/receiver_ptr_mutability.rs:+2:12: +2:13
+ StorageLive(_5); // scope 1 at $DIR/receiver_ptr_mutability.rs:+5:9: +5:16
+ StorageLive(_6); // scope 1 at $DIR/receiver_ptr_mutability.rs:+5:34: +5:41
+ StorageLive(_7); // scope 1 at $DIR/receiver_ptr_mutability.rs:+5:35: +5:41
+ StorageLive(_8); // scope 1 at $DIR/receiver_ptr_mutability.rs:+5:36: +5:41
+ StorageLive(_9); // scope 1 at $DIR/receiver_ptr_mutability.rs:+5:37: +5:41
+ _9 = &_1; // scope 1 at $DIR/receiver_ptr_mutability.rs:+5:37: +5:41
+ _8 = &_9; // scope 1 at $DIR/receiver_ptr_mutability.rs:+5:36: +5:41
+ _7 = &_8; // scope 1 at $DIR/receiver_ptr_mutability.rs:+5:35: +5:41
+ _6 = &_7; // scope 1 at $DIR/receiver_ptr_mutability.rs:+5:34: +5:41
+ _5 = &(*_6); // scope 1 at $DIR/receiver_ptr_mutability.rs:+5:34: +5:41
+ FakeRead(ForLet(None), _5); // scope 1 at $DIR/receiver_ptr_mutability.rs:+5:9: +5:16
+ AscribeUserType(_5, o, UserTypeProjection { base: UserType(3), projs: [] }); // scope 1 at $DIR/receiver_ptr_mutability.rs:+5:18: +5:31
+ StorageDead(_6); // scope 1 at $DIR/receiver_ptr_mutability.rs:+5:41: +5:42
+ StorageLive(_10); // scope 2 at $DIR/receiver_ptr_mutability.rs:+6:5: +6:16
+ StorageLive(_11); // scope 2 at $DIR/receiver_ptr_mutability.rs:+6:5: +6:16
+ StorageLive(_12); // scope 2 at $DIR/receiver_ptr_mutability.rs:+6:5: +6:16
+ _12 = (*(*(*(*_5)))); // scope 2 at $DIR/receiver_ptr_mutability.rs:+6:5: +6:16
+ _11 = move _12 as *const Test (Pointer(MutToConstPointer)); // scope 2 at $DIR/receiver_ptr_mutability.rs:+6:5: +6:16
+ StorageDead(_12); // scope 2 at $DIR/receiver_ptr_mutability.rs:+6:11: +6:12
+ _10 = Test::x(move _11) -> [return: bb3, unwind: bb4]; // scope 2 at $DIR/receiver_ptr_mutability.rs:+6:5: +6:16
+ // mir::Constant
+ // + span: $DIR/receiver_ptr_mutability.rs:19:13: 19:14
+ // + literal: Const { ty: fn(*const Test) {Test::x}, val: Value(<ZST>) }
+ }
+
+ bb3: {
+ StorageDead(_11); // scope 2 at $DIR/receiver_ptr_mutability.rs:+6:15: +6:16
+ StorageDead(_10); // scope 2 at $DIR/receiver_ptr_mutability.rs:+6:16: +6:17
+ _0 = const (); // scope 0 at $DIR/receiver_ptr_mutability.rs:+0:11: +7:2
+ StorageDead(_9); // scope 1 at $DIR/receiver_ptr_mutability.rs:+7:1: +7:2
+ StorageDead(_8); // scope 1 at $DIR/receiver_ptr_mutability.rs:+7:1: +7:2
+ StorageDead(_7); // scope 1 at $DIR/receiver_ptr_mutability.rs:+7:1: +7:2
+ StorageDead(_5); // scope 1 at $DIR/receiver_ptr_mutability.rs:+7:1: +7:2
+ StorageDead(_1); // scope 0 at $DIR/receiver_ptr_mutability.rs:+7:1: +7:2
+ return; // scope 0 at $DIR/receiver_ptr_mutability.rs:+7:2: +7:2
+ }
+
+ bb4 (cleanup): {
+ resume; // scope 0 at $DIR/receiver_ptr_mutability.rs:+0:1: +7:2
+ }
+}
--- /dev/null
+// EMIT_MIR receiver_ptr_mutability.main.built.after.mir
+
+#![feature(arbitrary_self_types)]
+
+struct Test {}
+
+impl Test {
+ fn x(self: *const Self) {
+ println!("x called");
+ }
+}
+
+fn main() {
+ let ptr: *mut Test = std::ptr::null_mut();
+ ptr.x();
+
+ // Test autoderefs
+ let ptr_ref: &&&&*mut Test = &&&&ptr;
+ ptr_ref.x();
+}
--- /dev/null
+// MIR for `match_bool` after built
+
+fn match_bool(_1: bool) -> usize {
+ debug x => _1; // in scope 0 at $DIR/simple_match.rs:+0:15: +0:16
+ let mut _0: usize; // return place in scope 0 at $DIR/simple_match.rs:+0:27: +0:32
+
+ bb0: {
+ FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/simple_match.rs:+1:11: +1:12
+ switchInt(_1) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/simple_match.rs:+1:5: +1:12
+ }
+
+ bb1: {
+ falseEdge -> [real: bb3, imaginary: bb2]; // scope 0 at $DIR/simple_match.rs:+2:9: +2:13
+ }
+
+ bb2: {
+ _0 = const 20_usize; // scope 0 at $DIR/simple_match.rs:+3:14: +3:16
+ goto -> bb4; // scope 0 at $DIR/simple_match.rs:+3:14: +3:16
+ }
+
+ bb3: {
+ _0 = const 10_usize; // scope 0 at $DIR/simple_match.rs:+2:17: +2:19
+ goto -> bb4; // scope 0 at $DIR/simple_match.rs:+2:17: +2:19
+ }
+
+ bb4: {
+ return; // scope 0 at $DIR/simple_match.rs:+5:2: +5:2
+ }
+}
--- /dev/null
+// Test that we don't generate unnecessarily large MIR for very simple matches
+
+
+// EMIT_MIR simple_match.match_bool.built.after.mir
+fn match_bool(x: bool) -> usize {
+ match x {
+ true => 10,
+ _ => 20,
+ }
+}
+
+fn main() {}
--- /dev/null
+// MIR for `XXX` after built
+
+static XXX: &Foo = {
+ let mut _0: &Foo; // return place in scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:13: +0:25
+ let _1: &Foo; // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:28: +18:2
+ let _2: Foo; // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:29: +18:2
+ let mut _3: &[(u32, u32)]; // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6
+ let mut _4: &[(u32, u32); 42]; // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6
+ let _5: &[(u32, u32); 42]; // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6
+ let _6: [(u32, u32); 42]; // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:12: +17:6
+ let mut _7: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:9: +3:15
+ let mut _8: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:17: +3:23
+ let mut _9: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:25: +3:31
+ let mut _10: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:9: +4:15
+ let mut _11: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:17: +4:23
+ let mut _12: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:25: +4:31
+ let mut _13: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:9: +5:15
+ let mut _14: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:17: +5:23
+ let mut _15: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:25: +5:31
+ let mut _16: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:9: +6:15
+ let mut _17: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:17: +6:23
+ let mut _18: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:25: +6:31
+ let mut _19: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:9: +7:15
+ let mut _20: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:17: +7:23
+ let mut _21: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:25: +7:31
+ let mut _22: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:9: +8:15
+ let mut _23: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:17: +8:23
+ let mut _24: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:25: +8:31
+ let mut _25: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:9: +9:15
+ let mut _26: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:17: +9:23
+ let mut _27: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:25: +9:31
+ let mut _28: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:9: +10:15
+ let mut _29: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:17: +10:23
+ let mut _30: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:25: +10:31
+ let mut _31: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:9: +11:15
+ let mut _32: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:17: +11:23
+ let mut _33: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:25: +11:31
+ let mut _34: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:9: +12:15
+ let mut _35: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:17: +12:23
+ let mut _36: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:25: +12:31
+ let mut _37: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:9: +13:15
+ let mut _38: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:17: +13:23
+ let mut _39: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:25: +13:31
+ let mut _40: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:9: +14:15
+ let mut _41: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:17: +14:23
+ let mut _42: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:25: +14:31
+ let mut _43: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:9: +15:15
+ let mut _44: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:17: +15:23
+ let mut _45: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:25: +15:31
+ let mut _46: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:9: +16:15
+ let mut _47: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:17: +16:23
+ let mut _48: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:25: +16:31
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:28: +18:2
+ StorageLive(_2); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:29: +18:2
+ StorageLive(_3); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6
+ StorageLive(_4); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6
+ StorageLive(_5); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6
+ StorageLive(_6); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:12: +17:6
+ StorageLive(_7); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:9: +3:15
+ _7 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:9: +3:15
+ StorageLive(_8); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:17: +3:23
+ _8 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:17: +3:23
+ StorageLive(_9); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:25: +3:31
+ _9 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:25: +3:31
+ StorageLive(_10); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:9: +4:15
+ _10 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:9: +4:15
+ StorageLive(_11); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:17: +4:23
+ _11 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:17: +4:23
+ StorageLive(_12); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:25: +4:31
+ _12 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:25: +4:31
+ StorageLive(_13); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:9: +5:15
+ _13 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:9: +5:15
+ StorageLive(_14); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:17: +5:23
+ _14 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:17: +5:23
+ StorageLive(_15); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:25: +5:31
+ _15 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:25: +5:31
+ StorageLive(_16); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:9: +6:15
+ _16 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:9: +6:15
+ StorageLive(_17); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:17: +6:23
+ _17 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:17: +6:23
+ StorageLive(_18); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:25: +6:31
+ _18 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:25: +6:31
+ StorageLive(_19); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:9: +7:15
+ _19 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:9: +7:15
+ StorageLive(_20); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:17: +7:23
+ _20 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:17: +7:23
+ StorageLive(_21); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:25: +7:31
+ _21 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:25: +7:31
+ StorageLive(_22); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:9: +8:15
+ _22 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:9: +8:15
+ StorageLive(_23); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:17: +8:23
+ _23 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:17: +8:23
+ StorageLive(_24); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:25: +8:31
+ _24 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:25: +8:31
+ StorageLive(_25); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:9: +9:15
+ _25 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:9: +9:15
+ StorageLive(_26); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:17: +9:23
+ _26 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:17: +9:23
+ StorageLive(_27); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:25: +9:31
+ _27 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:25: +9:31
+ StorageLive(_28); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:9: +10:15
+ _28 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:9: +10:15
+ StorageLive(_29); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:17: +10:23
+ _29 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:17: +10:23
+ StorageLive(_30); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:25: +10:31
+ _30 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:25: +10:31
+ StorageLive(_31); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:9: +11:15
+ _31 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:9: +11:15
+ StorageLive(_32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:17: +11:23
+ _32 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:17: +11:23
+ StorageLive(_33); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:25: +11:31
+ _33 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:25: +11:31
+ StorageLive(_34); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:9: +12:15
+ _34 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:9: +12:15
+ StorageLive(_35); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:17: +12:23
+ _35 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:17: +12:23
+ StorageLive(_36); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:25: +12:31
+ _36 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:25: +12:31
+ StorageLive(_37); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:9: +13:15
+ _37 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:9: +13:15
+ StorageLive(_38); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:17: +13:23
+ _38 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:17: +13:23
+ StorageLive(_39); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:25: +13:31
+ _39 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:25: +13:31
+ StorageLive(_40); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:9: +14:15
+ _40 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:9: +14:15
+ StorageLive(_41); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:17: +14:23
+ _41 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:17: +14:23
+ StorageLive(_42); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:25: +14:31
+ _42 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:25: +14:31
+ StorageLive(_43); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:9: +15:15
+ _43 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:9: +15:15
+ StorageLive(_44); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:17: +15:23
+ _44 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:17: +15:23
+ StorageLive(_45); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:25: +15:31
+ _45 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:25: +15:31
+ StorageLive(_46); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:9: +16:15
+ _46 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:9: +16:15
+ StorageLive(_47); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:17: +16:23
+ _47 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:17: +16:23
+ StorageLive(_48); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:25: +16:31
+ _48 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:25: +16:31
+ _6 = [move _7, move _8, move _9, move _10, move _11, move _12, move _13, move _14, move _15, move _16, move _17, move _18, move _19, move _20, move _21, move _22, move _23, move _24, move _25, move _26, move _27, move _28, move _29, move _30, move _31, move _32, move _33, move _34, move _35, move _36, move _37, move _38, move _39, move _40, move _41, move _42, move _43, move _44, move _45, move _46, move _47, move _48]; // scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:12: +17:6
+ StorageDead(_48); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_47); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_46); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_45); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_44); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_43); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_42); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_41); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_40); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_39); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_38); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_37); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_36); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_35); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_34); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_33); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_31); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_30); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_29); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_28); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_27); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_26); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_25); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_24); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_23); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_22); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_21); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_20); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_19); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_18); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_17); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_16); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_15); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_14); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_13); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_12); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_11); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_10); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_9); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_8); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ StorageDead(_7); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ _5 = &_6; // scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6
+ _4 = &(*_5); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6
+ _3 = move _4 as &[(u32, u32)] (Pointer(Unsize)); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6
+ StorageDead(_4); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
+ _2 = Foo { tup: const "hi", data: move _3 }; // scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:29: +18:2
+ // mir::Constant
+ // + span: $DIR/storage_live_dead_in_statics.rs:6:10: 6:14
+ // + literal: Const { ty: &str, val: Value(Slice(..)) }
+ StorageDead(_3); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+18:1: +18:2
+ _1 = &_2; // scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:28: +18:2
+ _0 = &(*_1); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:28: +18:2
+ StorageDead(_5); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+18:1: +18:2
+ StorageDead(_1); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+18:1: +18:2
+ return; // scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:1: +18:3
+ }
+}
--- /dev/null
+// Check that when we compile the static `XXX` into MIR, we do not
+// generate `StorageStart` or `StorageEnd` statements.
+
+// EMIT_MIR storage_live_dead_in_statics.XXX.built.after.mir
+static XXX: &'static Foo = &Foo {
+ tup: "hi",
+ data: &[
+ (0, 1), (0, 2), (0, 3),
+ (0, 1), (0, 2), (0, 3),
+ (0, 1), (0, 2), (0, 3),
+ (0, 1), (0, 2), (0, 3),
+ (0, 1), (0, 2), (0, 3),
+ (0, 1), (0, 2), (0, 3),
+ (0, 1), (0, 2), (0, 3),
+ (0, 1), (0, 2), (0, 3),
+ (0, 1), (0, 2), (0, 3),
+ (0, 1), (0, 2), (0, 3),
+ (0, 1), (0, 2), (0, 3),
+ (0, 1), (0, 2), (0, 3),
+ (0, 1), (0, 2), (0, 3),
+ (0, 1), (0, 2), (0, 3),
+ ]
+};
+
+#[derive(Debug)]
+struct Foo {
+ tup: &'static str,
+ data: &'static [(u32, u32)]
+}
+
+fn main() {
+ println!("{:?}", XXX);
+}
--- /dev/null
+// MIR for `move_out_by_subslice` after built
+
+fn move_out_by_subslice() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/uniform_array_move_out.rs:+0:27: +0:27
+ let _1: [std::boxed::Box<i32>; 2]; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:9: +1:10
+ let mut _2: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
+ let mut _3: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
+ let mut _4: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
+ let mut _5: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
+ let mut _6: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
+ let mut _7: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
+ let mut _8: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
+ let mut _9: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
+ let mut _10: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
+ let mut _11: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
+ scope 1 {
+ debug a => _1; // in scope 1 at $DIR/uniform_array_move_out.rs:+1:9: +1:10
+ let _12: [std::boxed::Box<i32>; 2]; // in scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:12
+ scope 4 {
+ debug _y => _12; // in scope 4 at $DIR/uniform_array_move_out.rs:+2:10: +2:12
+ }
+ }
+ scope 2 {
+ }
+ scope 3 {
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/uniform_array_move_out.rs:+1:9: +1:10
+ StorageLive(_2); // scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
+ _3 = SizeOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
+ _4 = AlignOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
+ _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb12]; // scope 2 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
+ // mir::Constant
+ // + span: $DIR/uniform_array_move_out.rs:11:14: 11:19
+ // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
+ }
+
+ bb1: {
+ StorageLive(_6); // scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
+ _6 = ShallowInitBox(move _5, i32); // scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
+ (*_6) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:+1:18: +1:19
+ _2 = move _6; // scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
+ drop(_6) -> [return: bb2, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:18: +1:19
+ }
+
+ bb2: {
+ StorageDead(_6); // scope 0 at $DIR/uniform_array_move_out.rs:+1:18: +1:19
+ StorageLive(_7); // scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
+ _8 = SizeOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
+ _9 = AlignOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
+ _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb11]; // scope 3 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
+ // mir::Constant
+ // + span: $DIR/uniform_array_move_out.rs:11:21: 11:26
+ // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
+ }
+
+ bb3: {
+ StorageLive(_11); // scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
+ _11 = ShallowInitBox(move _10, i32); // scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
+ (*_11) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:+1:25: +1:26
+ _7 = move _11; // scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
+ drop(_11) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:25: +1:26
+ }
+
+ bb4: {
+ StorageDead(_11); // scope 0 at $DIR/uniform_array_move_out.rs:+1:25: +1:26
+ _1 = [move _2, move _7]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:13: +1:27
+ drop(_7) -> [return: bb5, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
+ }
+
+ bb5: {
+ StorageDead(_7); // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
+ drop(_2) -> [return: bb6, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
+ }
+
+ bb6: {
+ StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
+ FakeRead(ForLet(None), _1); // scope 0 at $DIR/uniform_array_move_out.rs:+1:9: +1:10
+ StorageLive(_12); // scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:12
+ _12 = move _1[0..2]; // scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:12
+ _0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:+0:27: +3:2
+ drop(_12) -> [return: bb7, unwind: bb9]; // scope 1 at $DIR/uniform_array_move_out.rs:+3:1: +3:2
+ }
+
+ bb7: {
+ StorageDead(_12); // scope 1 at $DIR/uniform_array_move_out.rs:+3:1: +3:2
+ drop(_1) -> [return: bb8, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:+3:1: +3:2
+ }
+
+ bb8: {
+ StorageDead(_1); // scope 0 at $DIR/uniform_array_move_out.rs:+3:1: +3:2
+ return; // scope 0 at $DIR/uniform_array_move_out.rs:+3:2: +3:2
+ }
+
+ bb9 (cleanup): {
+ drop(_1) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:+3:1: +3:2
+ }
+
+ bb10 (cleanup): {
+ drop(_7) -> bb11; // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
+ }
+
+ bb11 (cleanup): {
+ drop(_2) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
+ }
+
+ bb12 (cleanup): {
+ resume; // scope 0 at $DIR/uniform_array_move_out.rs:+0:1: +3:2
+ }
+}
--- /dev/null
+// MIR for `move_out_from_end` after built
+
+fn move_out_from_end() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/uniform_array_move_out.rs:+0:24: +0:24
+ let _1: [std::boxed::Box<i32>; 2]; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:9: +1:10
+ let mut _2: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
+ let mut _3: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
+ let mut _4: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
+ let mut _5: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
+ let mut _6: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
+ let mut _7: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
+ let mut _8: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
+ let mut _9: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
+ let mut _10: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
+ let mut _11: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
+ scope 1 {
+ debug a => _1; // in scope 1 at $DIR/uniform_array_move_out.rs:+1:9: +1:10
+ let _12: std::boxed::Box<i32>; // in scope 1 at $DIR/uniform_array_move_out.rs:+2:14: +2:16
+ scope 4 {
+ debug _y => _12; // in scope 4 at $DIR/uniform_array_move_out.rs:+2:14: +2:16
+ }
+ }
+ scope 2 {
+ }
+ scope 3 {
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/uniform_array_move_out.rs:+1:9: +1:10
+ StorageLive(_2); // scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
+ _3 = SizeOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
+ _4 = AlignOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
+ _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb12]; // scope 2 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
+ // mir::Constant
+ // + span: $DIR/uniform_array_move_out.rs:5:14: 5:19
+ // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
+ }
+
+ bb1: {
+ StorageLive(_6); // scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
+ _6 = ShallowInitBox(move _5, i32); // scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
+ (*_6) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:+1:18: +1:19
+ _2 = move _6; // scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
+ drop(_6) -> [return: bb2, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:18: +1:19
+ }
+
+ bb2: {
+ StorageDead(_6); // scope 0 at $DIR/uniform_array_move_out.rs:+1:18: +1:19
+ StorageLive(_7); // scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
+ _8 = SizeOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
+ _9 = AlignOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
+ _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb11]; // scope 3 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
+ // mir::Constant
+ // + span: $DIR/uniform_array_move_out.rs:5:21: 5:26
+ // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
+ }
+
+ bb3: {
+ StorageLive(_11); // scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
+ _11 = ShallowInitBox(move _10, i32); // scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
+ (*_11) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:+1:25: +1:26
+ _7 = move _11; // scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
+ drop(_11) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:25: +1:26
+ }
+
+ bb4: {
+ StorageDead(_11); // scope 0 at $DIR/uniform_array_move_out.rs:+1:25: +1:26
+ _1 = [move _2, move _7]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:13: +1:27
+ drop(_7) -> [return: bb5, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
+ }
+
+ bb5: {
+ StorageDead(_7); // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
+ drop(_2) -> [return: bb6, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
+ }
+
+ bb6: {
+ StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
+ FakeRead(ForLet(None), _1); // scope 0 at $DIR/uniform_array_move_out.rs:+1:9: +1:10
+ StorageLive(_12); // scope 1 at $DIR/uniform_array_move_out.rs:+2:14: +2:16
+ _12 = move _1[1 of 2]; // scope 1 at $DIR/uniform_array_move_out.rs:+2:14: +2:16
+ _0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:+0:24: +3:2
+ drop(_12) -> [return: bb7, unwind: bb9]; // scope 1 at $DIR/uniform_array_move_out.rs:+3:1: +3:2
+ }
+
+ bb7: {
+ StorageDead(_12); // scope 1 at $DIR/uniform_array_move_out.rs:+3:1: +3:2
+ drop(_1) -> [return: bb8, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:+3:1: +3:2
+ }
+
+ bb8: {
+ StorageDead(_1); // scope 0 at $DIR/uniform_array_move_out.rs:+3:1: +3:2
+ return; // scope 0 at $DIR/uniform_array_move_out.rs:+3:2: +3:2
+ }
+
+ bb9 (cleanup): {
+ drop(_1) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:+3:1: +3:2
+ }
+
+ bb10 (cleanup): {
+ drop(_7) -> bb11; // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
+ }
+
+ bb11 (cleanup): {
+ drop(_2) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
+ }
+
+ bb12 (cleanup): {
+ resume; // scope 0 at $DIR/uniform_array_move_out.rs:+0:1: +3:2
+ }
+}
--- /dev/null
+#![feature(box_syntax)]
+
+// EMIT_MIR uniform_array_move_out.move_out_from_end.built.after.mir
+fn move_out_from_end() {
+ let a = [box 1, box 2];
+ let [.., _y] = a;
+}
+
+// EMIT_MIR uniform_array_move_out.move_out_by_subslice.built.after.mir
+fn move_out_by_subslice() {
+ let a = [box 1, box 2];
+ let [_y @ ..] = a;
+}
+
+fn main() {
+ move_out_by_subslice();
+ move_out_from_end();
+}
+++ /dev/null
-// ignore-endian-big
-extern "C" {
- static X: i32;
-}
-static Y: i32 = 42;
-
-// EMIT_MIR const_promotion_extern_static.BAR.PromoteTemps.diff
-// EMIT_MIR const_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir
-static mut BAR: *const &i32 = [&Y].as_ptr();
-
-// EMIT_MIR const_promotion_extern_static.FOO.PromoteTemps.diff
-// EMIT_MIR const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir
-static mut FOO: *const &i32 = [unsafe { &X }].as_ptr();
-
-// EMIT_MIR const_promotion_extern_static.BOP.mir_map.0.mir
-static BOP: &i32 = &13;
-
-fn main() {}
// MIR for `BAR::promoted[0]` after SimplifyCfg-elaborate-drops
promoted[0] in BAR: &[&i32; 1] = {
- let mut _0: &[&i32; 1]; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44
- let mut _1: [&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:35
- let mut _2: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:32: +0:34
- let mut _3: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:33: +0:34
+ let mut _0: &[&i32; 1]; // return place in scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:44
+ let mut _1: [&i32; 1]; // in scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:35
+ let mut _2: &i32; // in scope 0 at $DIR/const_promotion_extern_static.rs:+0:32: +0:34
+ let mut _3: &i32; // in scope 0 at $DIR/const_promotion_extern_static.rs:+0:33: +0:34
bb0: {
- _3 = const {alloc1: &i32}; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:33: +0:34
+ _3 = const {alloc1: &i32}; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:33: +0:34
// mir::Constant
- // + span: $DIR/const-promotion-extern-static.rs:9:33: 9:34
+ // + span: $DIR/const_promotion_extern_static.rs:9:33: 9:34
// + literal: Const { ty: &i32, val: Value(Scalar(alloc1)) }
- _2 = &(*_3); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:32: +0:34
- _1 = [move _2]; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:35
- _0 = &_1; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44
- return; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44
+ _2 = &(*_3); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:32: +0:34
+ _1 = [move _2]; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:35
+ _0 = &_1; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:44
+ return; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:44
}
}
+ // MIR for `BAR` after PromoteTemps
static mut BAR: *const &i32 = {
- let mut _0: *const &i32; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:+0:17: +0:28
- let mut _1: &[&i32]; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44
- let mut _2: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44
- let _3: [&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:35
- let mut _4: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:32: +0:34
- let _5: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:33: +0:34
-+ let mut _6: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44
+ let mut _0: *const &i32; // return place in scope 0 at $DIR/const_promotion_extern_static.rs:+0:17: +0:28
+ let mut _1: &[&i32]; // in scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:44
+ let mut _2: &[&i32; 1]; // in scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:44
+ let _3: [&i32; 1]; // in scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:35
+ let mut _4: &i32; // in scope 0 at $DIR/const_promotion_extern_static.rs:+0:32: +0:34
+ let _5: &i32; // in scope 0 at $DIR/const_promotion_extern_static.rs:+0:33: +0:34
++ let mut _6: &[&i32; 1]; // in scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:44
bb0: {
- StorageLive(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44
- StorageLive(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44
-- StorageLive(_3); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:35
-- StorageLive(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:32: +0:34
-- StorageLive(_5); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:33: +0:34
-- _5 = const {alloc1: &i32}; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:33: +0:34
-+ _6 = const _; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44
+ StorageLive(_1); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:44
+ StorageLive(_2); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:44
+- StorageLive(_3); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:35
+- StorageLive(_4); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:32: +0:34
+- StorageLive(_5); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:33: +0:34
+- _5 = const {alloc1: &i32}; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:33: +0:34
++ _6 = const _; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:44
// mir::Constant
-- // + span: $DIR/const-promotion-extern-static.rs:9:33: 9:34
+- // + span: $DIR/const_promotion_extern_static.rs:9:33: 9:34
- // + literal: Const { ty: &i32, val: Value(Scalar(alloc1)) }
-- _4 = &(*_5); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:32: +0:34
-- _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:35
-- _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44
-+ // + span: $DIR/const-promotion-extern-static.rs:9:31: 9:44
+- _4 = &(*_5); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:32: +0:34
+- _3 = [move _4]; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:35
+- _2 = &_3; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:44
++ // + span: $DIR/const_promotion_extern_static.rs:9:31: 9:44
+ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(BAR, [], Some(promoted[0])) }
-+ _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44
- _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44
-- StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:34: +0:35
- StorageDead(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:34: +0:35
- _0 = core::slice::<impl [&i32]>::as_ptr(move _1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:44
++ _2 = &(*_6); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:44
+ _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:44
+- StorageDead(_4); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:34: +0:35
+ StorageDead(_2); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:34: +0:35
+ _0 = core::slice::<impl [&i32]>::as_ptr(move _1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:44
// mir::Constant
- // + span: $DIR/const-promotion-extern-static.rs:9:36: 9:42
+ // + span: $DIR/const_promotion_extern_static.rs:9:36: 9:42
// + literal: Const { ty: for<'a> fn(&'a [&i32]) -> *const &i32 {core::slice::<impl [&i32]>::as_ptr}, val: Value(<ZST>) }
}
bb1: {
-- StorageDead(_5); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:43: +0:44
-- StorageDead(_3); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:43: +0:44
- StorageDead(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:43: +0:44
- return; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:1: +0:45
+- StorageDead(_5); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:43: +0:44
+- StorageDead(_3); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:43: +0:44
+ StorageDead(_1); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:43: +0:44
+ return; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:1: +0:45
}
bb2 (cleanup): {
- resume; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:1: +0:45
+ resume; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:1: +0:45
}
- }
-
--- /dev/null
+// MIR for `BOP` after built
+
+static BOP: &i32 = {
+ let mut _0: &i32; // return place in scope 0 at $DIR/const_promotion_extern_static.rs:+0:13: +0:17
+ let _1: &i32; // in scope 0 at $DIR/const_promotion_extern_static.rs:+0:20: +0:23
+ let _2: i32; // in scope 0 at $DIR/const_promotion_extern_static.rs:+0:21: +0:23
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:20: +0:23
+ StorageLive(_2); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:21: +0:23
+ _2 = const 13_i32; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:21: +0:23
+ _1 = &_2; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:20: +0:23
+ _0 = &(*_1); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:20: +0:23
+ StorageDead(_1); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:22: +0:23
+ return; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:1: +0:24
+ }
+}
+++ /dev/null
-// MIR for `BOP` 0 mir_map
-
-static BOP: &i32 = {
- let mut _0: &i32; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:+0:13: +0:17
- let _1: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:20: +0:23
- let _2: i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:21: +0:23
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:20: +0:23
- StorageLive(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:21: +0:23
- _2 = const 13_i32; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:21: +0:23
- _1 = &_2; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:20: +0:23
- _0 = &(*_1); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:20: +0:23
- StorageDead(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:22: +0:23
- return; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:1: +0:24
- }
-}
// MIR for `FOO::promoted[0]` after SimplifyCfg-elaborate-drops
promoted[0] in FOO: &[&i32; 1] = {
- let mut _0: &[&i32; 1]; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55
- let mut _1: [&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:46
- let mut _2: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:32: +0:45
- let mut _3: *const i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:42: +0:43
+ let mut _0: &[&i32; 1]; // return place in scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:55
+ let mut _1: [&i32; 1]; // in scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:46
+ let mut _2: &i32; // in scope 0 at $DIR/const_promotion_extern_static.rs:+0:32: +0:45
+ let mut _3: *const i32; // in scope 0 at $DIR/const_promotion_extern_static.rs:+0:42: +0:43
bb0: {
- _3 = const {alloc3: *const i32}; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:42: +0:43
+ _3 = const {alloc3: *const i32}; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:42: +0:43
// mir::Constant
- // + span: $DIR/const-promotion-extern-static.rs:13:42: 13:43
+ // + span: $DIR/const_promotion_extern_static.rs:13:42: 13:43
// + literal: Const { ty: *const i32, val: Value(Scalar(alloc3)) }
- _2 = &(*_3); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:41: +0:43
- _1 = [move _2]; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:46
- _0 = &_1; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55
- return; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55
+ _2 = &(*_3); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:41: +0:43
+ _1 = [move _2]; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:46
+ _0 = &_1; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:55
+ return; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:55
}
}
+ // MIR for `FOO` after PromoteTemps
static mut FOO: *const &i32 = {
- let mut _0: *const &i32; // return place in scope 0 at $DIR/const-promotion-extern-static.rs:+0:17: +0:28
- let mut _1: &[&i32]; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55
- let mut _2: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55
- let _3: [&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:46
- let mut _4: &i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:32: +0:45
- let _5: *const i32; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:42: +0:43
-+ let mut _6: &[&i32; 1]; // in scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55
+ let mut _0: *const &i32; // return place in scope 0 at $DIR/const_promotion_extern_static.rs:+0:17: +0:28
+ let mut _1: &[&i32]; // in scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:55
+ let mut _2: &[&i32; 1]; // in scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:55
+ let _3: [&i32; 1]; // in scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:46
+ let mut _4: &i32; // in scope 0 at $DIR/const_promotion_extern_static.rs:+0:32: +0:45
+ let _5: *const i32; // in scope 0 at $DIR/const_promotion_extern_static.rs:+0:42: +0:43
++ let mut _6: &[&i32; 1]; // in scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:55
scope 1 {
}
bb0: {
- StorageLive(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55
- StorageLive(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55
-- StorageLive(_3); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:46
-- StorageLive(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:32: +0:45
-- StorageLive(_5); // scope 1 at $DIR/const-promotion-extern-static.rs:+0:42: +0:43
-- _5 = const {alloc3: *const i32}; // scope 1 at $DIR/const-promotion-extern-static.rs:+0:42: +0:43
-+ _6 = const _; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55
+ StorageLive(_1); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:55
+ StorageLive(_2); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:55
+- StorageLive(_3); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:46
+- StorageLive(_4); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:32: +0:45
+- StorageLive(_5); // scope 1 at $DIR/const_promotion_extern_static.rs:+0:42: +0:43
+- _5 = const {alloc3: *const i32}; // scope 1 at $DIR/const_promotion_extern_static.rs:+0:42: +0:43
++ _6 = const _; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:55
// mir::Constant
-- // + span: $DIR/const-promotion-extern-static.rs:13:42: 13:43
+- // + span: $DIR/const_promotion_extern_static.rs:13:42: 13:43
- // + literal: Const { ty: *const i32, val: Value(Scalar(alloc3)) }
-- _4 = &(*_5); // scope 1 at $DIR/const-promotion-extern-static.rs:+0:41: +0:43
-- _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:46
-- _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55
-+ // + span: $DIR/const-promotion-extern-static.rs:13:31: 13:55
+- _4 = &(*_5); // scope 1 at $DIR/const_promotion_extern_static.rs:+0:41: +0:43
+- _3 = [move _4]; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:46
+- _2 = &_3; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:55
++ // + span: $DIR/const_promotion_extern_static.rs:13:31: 13:55
+ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(FOO, [], Some(promoted[0])) }
-+ _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55
- _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55
-- StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:45: +0:46
- StorageDead(_2); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:45: +0:46
- _0 = core::slice::<impl [&i32]>::as_ptr(move _1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:31: +0:55
++ _2 = &(*_6); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:55
+ _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:55
+- StorageDead(_4); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:45: +0:46
+ StorageDead(_2); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:45: +0:46
+ _0 = core::slice::<impl [&i32]>::as_ptr(move _1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:31: +0:55
// mir::Constant
- // + span: $DIR/const-promotion-extern-static.rs:13:47: 13:53
+ // + span: $DIR/const_promotion_extern_static.rs:13:47: 13:53
// + literal: Const { ty: for<'a> fn(&'a [&i32]) -> *const &i32 {core::slice::<impl [&i32]>::as_ptr}, val: Value(<ZST>) }
}
bb1: {
-- StorageDead(_5); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:54: +0:55
-- StorageDead(_3); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:54: +0:55
- StorageDead(_1); // scope 0 at $DIR/const-promotion-extern-static.rs:+0:54: +0:55
- return; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:1: +0:56
+- StorageDead(_5); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:54: +0:55
+- StorageDead(_3); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:54: +0:55
+ StorageDead(_1); // scope 0 at $DIR/const_promotion_extern_static.rs:+0:54: +0:55
+ return; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:1: +0:56
}
bb2 (cleanup): {
- resume; // scope 0 at $DIR/const-promotion-extern-static.rs:+0:1: +0:56
+ resume; // scope 0 at $DIR/const_promotion_extern_static.rs:+0:1: +0:56
}
}
-
--- /dev/null
+// ignore-endian-big
+extern "C" {
+ static X: i32;
+}
+static Y: i32 = 42;
+
+// EMIT_MIR const_promotion_extern_static.BAR.PromoteTemps.diff
+// EMIT_MIR const_promotion_extern_static.BAR-promoted[0].SimplifyCfg-elaborate-drops.after.mir
+static mut BAR: *const &i32 = [&Y].as_ptr();
+
+// EMIT_MIR const_promotion_extern_static.FOO.PromoteTemps.diff
+// EMIT_MIR const_promotion_extern_static.FOO-promoted[0].SimplifyCfg-elaborate-drops.after.mir
+static mut FOO: *const &i32 = [unsafe { &X }].as_ptr();
+
+// EMIT_MIR const_promotion_extern_static.BOP.built.after.mir
+static BOP: &i32 = &13;
+
+fn main() {}
+++ /dev/null
-// unit-test: ConstProp
-// compile-flags: -Zmir-opt-level=1
-
-trait NeedsDrop: Sized {
- const NEEDS: bool = std::mem::needs_drop::<Self>();
-}
-
-impl<This> NeedsDrop for This {}
-
-// EMIT_MIR control_flow_simplification.hello.ConstProp.diff
-// EMIT_MIR control_flow_simplification.hello.PreCodegen.before.mir
-fn hello<T>(){
- if <bool>::NEEDS {
- panic!()
- }
-}
-
-pub fn main() {
- hello::<()>();
- hello::<Vec<()>>();
-}
+ // MIR for `hello` after ConstProp
fn hello() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/control-flow-simplification.rs:+0:14: +0:14
- let mut _1: bool; // in scope 0 at $DIR/control-flow-simplification.rs:+1:8: +1:21
+ let mut _0: (); // return place in scope 0 at $DIR/control_flow_simplification.rs:+0:14: +0:14
+ let mut _1: bool; // in scope 0 at $DIR/control_flow_simplification.rs:+1:8: +1:21
let mut _2: !; // in scope 0 at $SRC_DIR/std/src/panic.rs:LL:COL
bb0: {
- StorageLive(_1); // scope 0 at $DIR/control-flow-simplification.rs:+1:8: +1:21
- _1 = const _; // scope 0 at $DIR/control-flow-simplification.rs:+1:8: +1:21
-- switchInt(move _1) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/control-flow-simplification.rs:+1:8: +1:21
-+ switchInt(const false) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/control-flow-simplification.rs:+1:8: +1:21
+ StorageLive(_1); // scope 0 at $DIR/control_flow_simplification.rs:+1:8: +1:21
+ _1 = const _; // scope 0 at $DIR/control_flow_simplification.rs:+1:8: +1:21
+- switchInt(move _1) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/control_flow_simplification.rs:+1:8: +1:21
++ switchInt(const false) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/control_flow_simplification.rs:+1:8: +1:21
}
bb1: {
}
bb2: {
- nop; // scope 0 at $DIR/control-flow-simplification.rs:+3:6: +3:6
- StorageDead(_1); // scope 0 at $DIR/control-flow-simplification.rs:+3:5: +3:6
- return; // scope 0 at $DIR/control-flow-simplification.rs:+4:2: +4:2
+ nop; // scope 0 at $DIR/control_flow_simplification.rs:+3:6: +3:6
+ StorageDead(_1); // scope 0 at $DIR/control_flow_simplification.rs:+3:5: +3:6
+ return; // scope 0 at $DIR/control_flow_simplification.rs:+4:2: +4:2
}
}
// MIR for `hello` before PreCodegen
fn hello() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/control-flow-simplification.rs:+0:14: +0:14
+ let mut _0: (); // return place in scope 0 at $DIR/control_flow_simplification.rs:+0:14: +0:14
bb0: {
- return; // scope 0 at $DIR/control-flow-simplification.rs:+4:2: +4:2
+ return; // scope 0 at $DIR/control_flow_simplification.rs:+4:2: +4:2
}
}
--- /dev/null
+// unit-test: ConstProp
+// compile-flags: -Zmir-opt-level=1
+
+trait NeedsDrop: Sized {
+ const NEEDS: bool = std::mem::needs_drop::<Self>();
+}
+
+impl<This> NeedsDrop for This {}
+
+// EMIT_MIR control_flow_simplification.hello.ConstProp.diff
+// EMIT_MIR control_flow_simplification.hello.PreCodegen.before.mir
+fn hello<T>(){
+ if <bool>::NEEDS {
+ panic!()
+ }
+}
+
+pub fn main() {
+ hello::<()>();
+ hello::<Vec<()>>();
+}
+++ /dev/null
-// unit-test: ConstProp
-// compile-flags: -Z mir-opt-level=3
-
-// Due to a bug in propagating scalar pairs the assertion below used to fail. In the expected
-// outputs below, after ConstProp this is how _2 would look like with the bug:
-//
-// _2 = (const Scalar(0x00) : (), const 0u8);
-//
-// Which has the wrong type.
-
-fn encode(this: ((), u8, u8)) {
- assert!(this.2 == 0);
-}
-
-// EMIT_MIR issue_66971.main.ConstProp.diff
-fn main() {
- encode(((), 0, 0));
-}
+++ /dev/null
-// unit-test: ConstProp
-// compile-flags: -Z mir-opt-level=3
-
-// This used to ICE in const-prop
-
-fn test(this: ((u8, u8),)) {
- assert!((this.0).0 == 1);
-}
-
-// EMIT_MIR issue_67019.main.ConstProp.diff
-fn main() {
- test(((1, 2),));
-}
+ // MIR for `main` after ConstProp
fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/issue-66971.rs:+0:11: +0:11
- let _1: (); // in scope 0 at $DIR/issue-66971.rs:+1:5: +1:23
- let mut _2: ((), u8, u8); // in scope 0 at $DIR/issue-66971.rs:+1:12: +1:22
- let mut _3: (); // in scope 0 at $DIR/issue-66971.rs:+1:13: +1:15
+ let mut _0: (); // return place in scope 0 at $DIR/issue_66971.rs:+0:11: +0:11
+ let _1: (); // in scope 0 at $DIR/issue_66971.rs:+1:5: +1:23
+ let mut _2: ((), u8, u8); // in scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
+ let mut _3: (); // in scope 0 at $DIR/issue_66971.rs:+1:13: +1:15
bb0: {
- StorageLive(_1); // scope 0 at $DIR/issue-66971.rs:+1:5: +1:23
- StorageLive(_2); // scope 0 at $DIR/issue-66971.rs:+1:12: +1:22
- StorageLive(_3); // scope 0 at $DIR/issue-66971.rs:+1:13: +1:15
- nop; // scope 0 at $DIR/issue-66971.rs:+1:13: +1:15
- Deinit(_2); // scope 0 at $DIR/issue-66971.rs:+1:12: +1:22
- nop; // scope 0 at $DIR/issue-66971.rs:+1:12: +1:22
- (_2.1: u8) = const 0_u8; // scope 0 at $DIR/issue-66971.rs:+1:12: +1:22
- (_2.2: u8) = const 0_u8; // scope 0 at $DIR/issue-66971.rs:+1:12: +1:22
- StorageDead(_3); // scope 0 at $DIR/issue-66971.rs:+1:21: +1:22
- _1 = encode(move _2) -> bb1; // scope 0 at $DIR/issue-66971.rs:+1:5: +1:23
+ StorageLive(_1); // scope 0 at $DIR/issue_66971.rs:+1:5: +1:23
+ StorageLive(_2); // scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
+ StorageLive(_3); // scope 0 at $DIR/issue_66971.rs:+1:13: +1:15
+ nop; // scope 0 at $DIR/issue_66971.rs:+1:13: +1:15
+ Deinit(_2); // scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
+ nop; // scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
+ (_2.1: u8) = const 0_u8; // scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
+ (_2.2: u8) = const 0_u8; // scope 0 at $DIR/issue_66971.rs:+1:12: +1:22
+ StorageDead(_3); // scope 0 at $DIR/issue_66971.rs:+1:21: +1:22
+ _1 = encode(move _2) -> bb1; // scope 0 at $DIR/issue_66971.rs:+1:5: +1:23
// mir::Constant
- // + span: $DIR/issue-66971.rs:17:5: 17:11
+ // + span: $DIR/issue_66971.rs:17:5: 17:11
// + literal: Const { ty: fn(((), u8, u8)) {encode}, val: Value(<ZST>) }
}
bb1: {
- StorageDead(_2); // scope 0 at $DIR/issue-66971.rs:+1:22: +1:23
- StorageDead(_1); // scope 0 at $DIR/issue-66971.rs:+1:23: +1:24
- nop; // scope 0 at $DIR/issue-66971.rs:+0:11: +2:2
- return; // scope 0 at $DIR/issue-66971.rs:+2:2: +2:2
+ StorageDead(_2); // scope 0 at $DIR/issue_66971.rs:+1:22: +1:23
+ StorageDead(_1); // scope 0 at $DIR/issue_66971.rs:+1:23: +1:24
+ nop; // scope 0 at $DIR/issue_66971.rs:+0:11: +2:2
+ return; // scope 0 at $DIR/issue_66971.rs:+2:2: +2:2
}
}
--- /dev/null
+// unit-test: ConstProp
+// compile-flags: -Z mir-opt-level=3
+
+// Due to a bug in propagating scalar pairs the assertion below used to fail. In the expected
+// outputs below, after ConstProp this is how _2 would look like with the bug:
+//
+// _2 = (const Scalar(0x00) : (), const 0u8);
+//
+// Which has the wrong type.
+
+fn encode(this: ((), u8, u8)) {
+ assert!(this.2 == 0);
+}
+
+// EMIT_MIR issue_66971.main.ConstProp.diff
+fn main() {
+ encode(((), 0, 0));
+}
+ // MIR for `main` after ConstProp
fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/issue-67019.rs:+0:11: +0:11
- let _1: (); // in scope 0 at $DIR/issue-67019.rs:+1:5: +1:20
- let mut _2: ((u8, u8),); // in scope 0 at $DIR/issue-67019.rs:+1:10: +1:19
- let mut _3: (u8, u8); // in scope 0 at $DIR/issue-67019.rs:+1:11: +1:17
+ let mut _0: (); // return place in scope 0 at $DIR/issue_67019.rs:+0:11: +0:11
+ let _1: (); // in scope 0 at $DIR/issue_67019.rs:+1:5: +1:20
+ let mut _2: ((u8, u8),); // in scope 0 at $DIR/issue_67019.rs:+1:10: +1:19
+ let mut _3: (u8, u8); // in scope 0 at $DIR/issue_67019.rs:+1:11: +1:17
bb0: {
- StorageLive(_1); // scope 0 at $DIR/issue-67019.rs:+1:5: +1:20
- StorageLive(_2); // scope 0 at $DIR/issue-67019.rs:+1:10: +1:19
- StorageLive(_3); // scope 0 at $DIR/issue-67019.rs:+1:11: +1:17
- Deinit(_3); // scope 0 at $DIR/issue-67019.rs:+1:11: +1:17
- (_3.0: u8) = const 1_u8; // scope 0 at $DIR/issue-67019.rs:+1:11: +1:17
- (_3.1: u8) = const 2_u8; // scope 0 at $DIR/issue-67019.rs:+1:11: +1:17
- Deinit(_2); // scope 0 at $DIR/issue-67019.rs:+1:10: +1:19
-- (_2.0: (u8, u8)) = move _3; // scope 0 at $DIR/issue-67019.rs:+1:10: +1:19
-+ (_2.0: (u8, u8)) = const (1_u8, 2_u8); // scope 0 at $DIR/issue-67019.rs:+1:10: +1:19
- StorageDead(_3); // scope 0 at $DIR/issue-67019.rs:+1:18: +1:19
- _1 = test(move _2) -> bb1; // scope 0 at $DIR/issue-67019.rs:+1:5: +1:20
+ StorageLive(_1); // scope 0 at $DIR/issue_67019.rs:+1:5: +1:20
+ StorageLive(_2); // scope 0 at $DIR/issue_67019.rs:+1:10: +1:19
+ StorageLive(_3); // scope 0 at $DIR/issue_67019.rs:+1:11: +1:17
+ Deinit(_3); // scope 0 at $DIR/issue_67019.rs:+1:11: +1:17
+ (_3.0: u8) = const 1_u8; // scope 0 at $DIR/issue_67019.rs:+1:11: +1:17
+ (_3.1: u8) = const 2_u8; // scope 0 at $DIR/issue_67019.rs:+1:11: +1:17
+ Deinit(_2); // scope 0 at $DIR/issue_67019.rs:+1:10: +1:19
+- (_2.0: (u8, u8)) = move _3; // scope 0 at $DIR/issue_67019.rs:+1:10: +1:19
++ (_2.0: (u8, u8)) = const (1_u8, 2_u8); // scope 0 at $DIR/issue_67019.rs:+1:10: +1:19
+ StorageDead(_3); // scope 0 at $DIR/issue_67019.rs:+1:18: +1:19
+ _1 = test(move _2) -> bb1; // scope 0 at $DIR/issue_67019.rs:+1:5: +1:20
// mir::Constant
- // + span: $DIR/issue-67019.rs:12:5: 12:9
+ // + span: $DIR/issue_67019.rs:12:5: 12:9
// + literal: Const { ty: fn(((u8, u8),)) {test}, val: Value(<ZST>) }
}
bb1: {
- StorageDead(_2); // scope 0 at $DIR/issue-67019.rs:+1:19: +1:20
- StorageDead(_1); // scope 0 at $DIR/issue-67019.rs:+1:20: +1:21
- nop; // scope 0 at $DIR/issue-67019.rs:+0:11: +2:2
- return; // scope 0 at $DIR/issue-67019.rs:+2:2: +2:2
+ StorageDead(_2); // scope 0 at $DIR/issue_67019.rs:+1:19: +1:20
+ StorageDead(_1); // scope 0 at $DIR/issue_67019.rs:+1:20: +1:21
+ nop; // scope 0 at $DIR/issue_67019.rs:+0:11: +2:2
+ return; // scope 0 at $DIR/issue_67019.rs:+2:2: +2:2
}
}
--- /dev/null
+// unit-test: ConstProp
+// compile-flags: -Z mir-opt-level=3
+
+// This used to ICE in const-prop
+
+fn test(this: ((u8, u8),)) {
+ assert!((this.0).0 == 1);
+}
+
+// EMIT_MIR issue_67019.main.ConstProp.diff
+fn main() {
+ test(((1, 2),));
+}
+++ /dev/null
-// MIR for `bar` 0 mir_map
-
-fn bar(_1: Bar) -> usize {
- debug bar => _1; // in scope 0 at $DIR/enum_cast.rs:+0:8: +0:11
- let mut _0: usize; // return place in scope 0 at $DIR/enum_cast.rs:+0:21: +0:26
- let _2: Bar; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
- let mut _3: isize; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
- _2 = move _1; // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
- _3 = discriminant(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
- _0 = move _3 as usize (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
- StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+1:16: +1:17
- return; // scope 0 at $DIR/enum_cast.rs:+2:2: +2:2
- }
-}
+++ /dev/null
-// MIR for `boo` 0 mir_map
-
-fn boo(_1: Boo) -> usize {
- debug boo => _1; // in scope 0 at $DIR/enum_cast.rs:+0:8: +0:11
- let mut _0: usize; // return place in scope 0 at $DIR/enum_cast.rs:+0:21: +0:26
- let _2: Boo; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
- let mut _3: u8; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
- _2 = move _1; // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
- _3 = discriminant(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
- _0 = move _3 as usize (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
- StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+1:16: +1:17
- return; // scope 0 at $DIR/enum_cast.rs:+2:2: +2:2
- }
-}
+++ /dev/null
-// MIR for `droppy` 0 mir_map
-
-fn droppy() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/enum_cast.rs:+0:13: +0:13
- let _1: (); // in scope 0 at $DIR/enum_cast.rs:+1:5: +6:6
- let _2: Droppy; // in scope 0 at $DIR/enum_cast.rs:+2:13: +2:14
- let _4: Droppy; // in scope 0 at $DIR/enum_cast.rs:+5:17: +5:18
- let mut _5: isize; // in scope 0 at $DIR/enum_cast.rs:+5:17: +5:18
- let _6: Droppy; // in scope 0 at $DIR/enum_cast.rs:+7:9: +7:10
- scope 1 {
- debug x => _2; // in scope 1 at $DIR/enum_cast.rs:+2:13: +2:14
- scope 2 {
- debug y => _3; // in scope 2 at $DIR/enum_cast.rs:+5:13: +5:14
- }
- scope 3 {
- let _3: usize; // in scope 3 at $DIR/enum_cast.rs:+5:13: +5:14
- }
- }
- scope 4 {
- debug z => _6; // in scope 4 at $DIR/enum_cast.rs:+7:9: +7:10
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/enum_cast.rs:+1:5: +6:6
- StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+2:13: +2:14
- _2 = Droppy::C; // scope 0 at $DIR/enum_cast.rs:+2:17: +2:26
- FakeRead(ForLet(None), _2); // scope 0 at $DIR/enum_cast.rs:+2:13: +2:14
- StorageLive(_3); // scope 3 at $DIR/enum_cast.rs:+5:13: +5:14
- StorageLive(_4); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:18
- _4 = move _2; // scope 3 at $DIR/enum_cast.rs:+5:17: +5:18
- _5 = discriminant(_4); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
- _3 = move _5 as usize (IntToInt); // scope 3 at $DIR/enum_cast.rs:+5:17: +5:27
- drop(_4) -> [return: bb1, unwind: bb4]; // scope 3 at $DIR/enum_cast.rs:+5:26: +5:27
- }
-
- bb1: {
- StorageDead(_4); // scope 3 at $DIR/enum_cast.rs:+5:26: +5:27
- FakeRead(ForLet(None), _3); // scope 3 at $DIR/enum_cast.rs:+5:13: +5:14
- _1 = const (); // scope 0 at $DIR/enum_cast.rs:+1:5: +6:6
- StorageDead(_3); // scope 1 at $DIR/enum_cast.rs:+6:5: +6:6
- drop(_2) -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/enum_cast.rs:+6:5: +6:6
- }
-
- bb2: {
- StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+6:5: +6:6
- StorageDead(_1); // scope 0 at $DIR/enum_cast.rs:+6:5: +6:6
- StorageLive(_6); // scope 0 at $DIR/enum_cast.rs:+7:9: +7:10
- _6 = Droppy::B; // scope 0 at $DIR/enum_cast.rs:+7:13: +7:22
- FakeRead(ForLet(None), _6); // scope 0 at $DIR/enum_cast.rs:+7:9: +7:10
- _0 = const (); // scope 0 at $DIR/enum_cast.rs:+0:13: +8:2
- drop(_6) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/enum_cast.rs:+8:1: +8:2
- }
-
- bb3: {
- StorageDead(_6); // scope 0 at $DIR/enum_cast.rs:+8:1: +8:2
- return; // scope 0 at $DIR/enum_cast.rs:+8:2: +8:2
- }
-
- bb4 (cleanup): {
- drop(_2) -> bb5; // scope 0 at $DIR/enum_cast.rs:+6:5: +6:6
- }
-
- bb5 (cleanup): {
- resume; // scope 0 at $DIR/enum_cast.rs:+0:1: +8:2
- }
-}
+++ /dev/null
-// MIR for `foo` 0 mir_map
-
-fn foo(_1: Foo) -> usize {
- debug foo => _1; // in scope 0 at $DIR/enum_cast.rs:+0:8: +0:11
- let mut _0: usize; // return place in scope 0 at $DIR/enum_cast.rs:+0:21: +0:26
- let _2: Foo; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
- let mut _3: isize; // in scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
- _2 = move _1; // scope 0 at $DIR/enum_cast.rs:+1:5: +1:8
- _3 = discriminant(_2); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
- _0 = move _3 as usize (IntToInt); // scope 0 at $DIR/enum_cast.rs:+1:5: +1:17
- StorageDead(_2); // scope 0 at $DIR/enum_cast.rs:+1:16: +1:17
- return; // scope 0 at $DIR/enum_cast.rs:+2:2: +2:2
- }
-}
+++ /dev/null
-// EMIT_MIR enum_cast.foo.mir_map.0.mir
-// EMIT_MIR enum_cast.bar.mir_map.0.mir
-// EMIT_MIR enum_cast.boo.mir_map.0.mir
-
-enum Foo {
- A
-}
-
-enum Bar {
- A, B
-}
-
-#[repr(u8)]
-enum Boo {
- A, B
-}
-
-fn foo(foo: Foo) -> usize {
- foo as usize
-}
-
-fn bar(bar: Bar) -> usize {
- bar as usize
-}
-
-fn boo(boo: Boo) -> usize {
- boo as usize
-}
-
-// EMIT_MIR enum_cast.droppy.mir_map.0.mir
-enum Droppy {
- A, B, C
-}
-
-impl Drop for Droppy {
- fn drop(&mut self) {}
-}
-
-fn droppy() {
- {
- let x = Droppy::C;
- // remove this entire test once `cenum_impl_drop_cast` becomes a hard error
- #[allow(cenum_impl_drop_cast)]
- let y = x as usize;
- }
- let z = Droppy::B;
-}
-
-fn main() {
-}
+++ /dev/null
-// Test that simple or-patterns don't get expanded to exponentially large CFGs
-
-// EMIT_MIR exponential_or.match_tuple.SimplifyCfg-initial.after.mir
-fn match_tuple(x: (u32, bool, Option<i32>, u32)) -> u32 {
- match x {
- (y @ (1 | 4), true | false, Some(1 | 8) | None, z @ (6..=9 | 13..=16)) => y ^ z,
- _ => 0,
- }
-}
-
-fn main() {}
// MIR for `match_tuple` after SimplifyCfg-initial
fn match_tuple(_1: (u32, bool, Option<i32>, u32)) -> u32 {
- debug x => _1; // in scope 0 at $DIR/exponential-or.rs:+0:16: +0:17
- let mut _0: u32; // return place in scope 0 at $DIR/exponential-or.rs:+0:53: +0:56
- let mut _2: isize; // in scope 0 at $DIR/exponential-or.rs:+2:37: +2:48
- let mut _3: bool; // in scope 0 at $DIR/exponential-or.rs:+2:70: +2:77
- let mut _4: bool; // in scope 0 at $DIR/exponential-or.rs:+2:70: +2:77
- let mut _5: bool; // in scope 0 at $DIR/exponential-or.rs:+2:62: +2:67
- let mut _6: bool; // in scope 0 at $DIR/exponential-or.rs:+2:62: +2:67
- let _7: u32; // in scope 0 at $DIR/exponential-or.rs:+2:10: +2:11
- let _8: u32; // in scope 0 at $DIR/exponential-or.rs:+2:57: +2:58
- let mut _9: u32; // in scope 0 at $DIR/exponential-or.rs:+2:83: +2:84
- let mut _10: u32; // in scope 0 at $DIR/exponential-or.rs:+2:87: +2:88
+ debug x => _1; // in scope 0 at $DIR/exponential_or.rs:+0:16: +0:17
+ let mut _0: u32; // return place in scope 0 at $DIR/exponential_or.rs:+0:53: +0:56
+ let mut _2: isize; // in scope 0 at $DIR/exponential_or.rs:+2:37: +2:48
+ let mut _3: bool; // in scope 0 at $DIR/exponential_or.rs:+2:70: +2:77
+ let mut _4: bool; // in scope 0 at $DIR/exponential_or.rs:+2:70: +2:77
+ let mut _5: bool; // in scope 0 at $DIR/exponential_or.rs:+2:62: +2:67
+ let mut _6: bool; // in scope 0 at $DIR/exponential_or.rs:+2:62: +2:67
+ let _7: u32; // in scope 0 at $DIR/exponential_or.rs:+2:10: +2:11
+ let _8: u32; // in scope 0 at $DIR/exponential_or.rs:+2:57: +2:58
+ let mut _9: u32; // in scope 0 at $DIR/exponential_or.rs:+2:83: +2:84
+ let mut _10: u32; // in scope 0 at $DIR/exponential_or.rs:+2:87: +2:88
scope 1 {
- debug y => _7; // in scope 1 at $DIR/exponential-or.rs:+2:10: +2:11
- debug z => _8; // in scope 1 at $DIR/exponential-or.rs:+2:57: +2:58
+ debug y => _7; // in scope 1 at $DIR/exponential_or.rs:+2:10: +2:11
+ debug z => _8; // in scope 1 at $DIR/exponential_or.rs:+2:57: +2:58
}
bb0: {
- FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/exponential-or.rs:+1:11: +1:12
- switchInt((_1.0: u32)) -> [1_u32: bb2, 4_u32: bb2, otherwise: bb1]; // scope 0 at $DIR/exponential-or.rs:+2:15: +2:20
+ FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/exponential_or.rs:+1:11: +1:12
+ switchInt((_1.0: u32)) -> [1_u32: bb2, 4_u32: bb2, otherwise: bb1]; // scope 0 at $DIR/exponential_or.rs:+2:15: +2:20
}
bb1: {
- _0 = const 0_u32; // scope 0 at $DIR/exponential-or.rs:+3:14: +3:15
- goto -> bb10; // scope 0 at $DIR/exponential-or.rs:+3:14: +3:15
+ _0 = const 0_u32; // scope 0 at $DIR/exponential_or.rs:+3:14: +3:15
+ goto -> bb10; // scope 0 at $DIR/exponential_or.rs:+3:14: +3:15
}
bb2: {
- _2 = discriminant((_1.2: std::option::Option<i32>)); // scope 0 at $DIR/exponential-or.rs:+2:37: +2:55
- switchInt(move _2) -> [0_isize: bb4, 1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/exponential-or.rs:+2:37: +2:55
+ _2 = discriminant((_1.2: std::option::Option<i32>)); // scope 0 at $DIR/exponential_or.rs:+2:37: +2:55
+ switchInt(move _2) -> [0_isize: bb4, 1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/exponential_or.rs:+2:37: +2:55
}
bb3: {
- switchInt((((_1.2: std::option::Option<i32>) as Some).0: i32)) -> [1_i32: bb4, 8_i32: bb4, otherwise: bb1]; // scope 0 at $DIR/exponential-or.rs:+2:37: +2:55
+ switchInt((((_1.2: std::option::Option<i32>) as Some).0: i32)) -> [1_i32: bb4, 8_i32: bb4, otherwise: bb1]; // scope 0 at $DIR/exponential_or.rs:+2:37: +2:55
}
bb4: {
- _5 = Le(const 6_u32, (_1.3: u32)); // scope 0 at $DIR/exponential-or.rs:+2:62: +2:67
- switchInt(move _5) -> [false: bb6, otherwise: bb5]; // scope 0 at $DIR/exponential-or.rs:+2:62: +2:67
+ _5 = Le(const 6_u32, (_1.3: u32)); // scope 0 at $DIR/exponential_or.rs:+2:62: +2:67
+ switchInt(move _5) -> [false: bb6, otherwise: bb5]; // scope 0 at $DIR/exponential_or.rs:+2:62: +2:67
}
bb5: {
- _6 = Le((_1.3: u32), const 9_u32); // scope 0 at $DIR/exponential-or.rs:+2:62: +2:67
- switchInt(move _6) -> [false: bb6, otherwise: bb8]; // scope 0 at $DIR/exponential-or.rs:+2:62: +2:67
+ _6 = Le((_1.3: u32), const 9_u32); // scope 0 at $DIR/exponential_or.rs:+2:62: +2:67
+ switchInt(move _6) -> [false: bb6, otherwise: bb8]; // scope 0 at $DIR/exponential_or.rs:+2:62: +2:67
}
bb6: {
- _3 = Le(const 13_u32, (_1.3: u32)); // scope 0 at $DIR/exponential-or.rs:+2:70: +2:77
- switchInt(move _3) -> [false: bb1, otherwise: bb7]; // scope 0 at $DIR/exponential-or.rs:+2:70: +2:77
+ _3 = Le(const 13_u32, (_1.3: u32)); // scope 0 at $DIR/exponential_or.rs:+2:70: +2:77
+ switchInt(move _3) -> [false: bb1, otherwise: bb7]; // scope 0 at $DIR/exponential_or.rs:+2:70: +2:77
}
bb7: {
- _4 = Le((_1.3: u32), const 16_u32); // scope 0 at $DIR/exponential-or.rs:+2:70: +2:77
- switchInt(move _4) -> [false: bb1, otherwise: bb8]; // scope 0 at $DIR/exponential-or.rs:+2:70: +2:77
+ _4 = Le((_1.3: u32), const 16_u32); // scope 0 at $DIR/exponential_or.rs:+2:70: +2:77
+ switchInt(move _4) -> [false: bb1, otherwise: bb8]; // scope 0 at $DIR/exponential_or.rs:+2:70: +2:77
}
bb8: {
- falseEdge -> [real: bb9, imaginary: bb1]; // scope 0 at $DIR/exponential-or.rs:+2:9: +2:79
+ falseEdge -> [real: bb9, imaginary: bb1]; // scope 0 at $DIR/exponential_or.rs:+2:9: +2:79
}
bb9: {
- StorageLive(_7); // scope 0 at $DIR/exponential-or.rs:+2:10: +2:11
- _7 = (_1.0: u32); // scope 0 at $DIR/exponential-or.rs:+2:10: +2:11
- StorageLive(_8); // scope 0 at $DIR/exponential-or.rs:+2:57: +2:58
- _8 = (_1.3: u32); // scope 0 at $DIR/exponential-or.rs:+2:57: +2:58
- StorageLive(_9); // scope 1 at $DIR/exponential-or.rs:+2:83: +2:84
- _9 = _7; // scope 1 at $DIR/exponential-or.rs:+2:83: +2:84
- StorageLive(_10); // scope 1 at $DIR/exponential-or.rs:+2:87: +2:88
- _10 = _8; // scope 1 at $DIR/exponential-or.rs:+2:87: +2:88
- _0 = BitXor(move _9, move _10); // scope 1 at $DIR/exponential-or.rs:+2:83: +2:88
- StorageDead(_10); // scope 1 at $DIR/exponential-or.rs:+2:87: +2:88
- StorageDead(_9); // scope 1 at $DIR/exponential-or.rs:+2:87: +2:88
- StorageDead(_8); // scope 0 at $DIR/exponential-or.rs:+2:87: +2:88
- StorageDead(_7); // scope 0 at $DIR/exponential-or.rs:+2:87: +2:88
- goto -> bb10; // scope 0 at $DIR/exponential-or.rs:+2:87: +2:88
+ StorageLive(_7); // scope 0 at $DIR/exponential_or.rs:+2:10: +2:11
+ _7 = (_1.0: u32); // scope 0 at $DIR/exponential_or.rs:+2:10: +2:11
+ StorageLive(_8); // scope 0 at $DIR/exponential_or.rs:+2:57: +2:58
+ _8 = (_1.3: u32); // scope 0 at $DIR/exponential_or.rs:+2:57: +2:58
+ StorageLive(_9); // scope 1 at $DIR/exponential_or.rs:+2:83: +2:84
+ _9 = _7; // scope 1 at $DIR/exponential_or.rs:+2:83: +2:84
+ StorageLive(_10); // scope 1 at $DIR/exponential_or.rs:+2:87: +2:88
+ _10 = _8; // scope 1 at $DIR/exponential_or.rs:+2:87: +2:88
+ _0 = BitXor(move _9, move _10); // scope 1 at $DIR/exponential_or.rs:+2:83: +2:88
+ StorageDead(_10); // scope 1 at $DIR/exponential_or.rs:+2:87: +2:88
+ StorageDead(_9); // scope 1 at $DIR/exponential_or.rs:+2:87: +2:88
+ StorageDead(_8); // scope 0 at $DIR/exponential_or.rs:+2:87: +2:88
+ StorageDead(_7); // scope 0 at $DIR/exponential_or.rs:+2:87: +2:88
+ goto -> bb10; // scope 0 at $DIR/exponential_or.rs:+2:87: +2:88
}
bb10: {
- return; // scope 0 at $DIR/exponential-or.rs:+5:2: +5:2
+ return; // scope 0 at $DIR/exponential_or.rs:+5:2: +5:2
}
}
--- /dev/null
+// Test that simple or-patterns don't get expanded to exponentially large CFGs
+
+// EMIT_MIR exponential_or.match_tuple.SimplifyCfg-initial.after.mir
+fn match_tuple(x: (u32, bool, Option<i32>, u32)) -> u32 {
+ match x {
+ (y @ (1 | 4), true | false, Some(1 | 8) | None, z @ (6..=9 | 13..=16)) => y ^ z,
+ _ => 0,
+ }
+}
+
+fn main() {}
+++ /dev/null
-// compile-flags: -Zmir-opt-level=0
-
-// Tests that the `<fn() as Fn>` shim does not create a `Call` terminator with a `Self` callee
-// (as only `FnDef` and `FnPtr` callees are allowed in MIR).
-
-// EMIT_MIR core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir
-fn main() {
- call(noop as fn());
-}
-
-fn noop() {}
-
-fn call<F: Fn()>(f: F) {
- f();
-}
--- /dev/null
+// compile-flags: -Zmir-opt-level=0
+
+// Tests that the `<fn() as Fn>` shim does not create a `Call` terminator with a `Self` callee
+// (as only `FnDef` and `FnPtr` callees are allowed in MIR).
+
+// EMIT_MIR core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir
+fn main() {
+ call(noop as fn());
+}
+
+fn noop() {}
+
+fn call<F: Fn()>(f: F) {
+ f();
+}
+++ /dev/null
-#![feature(generators, generator_trait)]
-
-// ignore-wasm32-bare compiled with panic=abort by default
-
-// Regression test for #58892, generator drop shims should not have blocks
-// spuriously marked as cleanup
-
-// EMIT_MIR generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir
-fn main() {
- let gen = || {
- let _s = String::new();
- yield;
- };
-}
+++ /dev/null
-// ignore-wasm32-bare compiled with panic=abort by default
-
-// Test that we generate StorageDead on unwind paths for generators.
-//
-// Basic block and local names can safely change, but the StorageDead statements
-// should not go away.
-
-#![feature(generators, generator_trait)]
-
-struct Foo(i32);
-
-impl Drop for Foo {
- fn drop(&mut self) {}
-}
-
-struct Bar(i32);
-
-fn take<T>(_x: T) {}
-
-// EMIT_MIR generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir
-fn main() {
- let _gen = || {
- let a = Foo(5);
- let b = Bar(6);
- yield;
- take(a);
- take(b);
- };
-}
+++ /dev/null
-//! Tests that generators that cannot return or unwind don't have unnecessary
-//! panic branches.
-
-// compile-flags: -C panic=abort
-// no-prefer-dynamic
-
-#![feature(generators, generator_trait)]
-
-struct HasDrop;
-
-impl Drop for HasDrop {
- fn drop(&mut self) {}
-}
-
-fn callee() {}
-
-// EMIT_MIR generator_tiny.main-{closure#0}.generator_resume.0.mir
-fn main() {
- let _gen = |_x: u8| {
- let _d = HasDrop;
- loop {
- yield;
- callee();
- }
- };
-}
},
} */
-fn main::{closure#0}(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 10:17]) -> () {
- let mut _0: (); // return place in scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +3:6
- let mut _2: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +3:6
- let _3: std::string::String; // in scope 0 at $DIR/generator-drop-cleanup.rs:+1:13: +1:15
- let _4: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:+2:9: +2:14
- let mut _5: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:+2:9: +2:14
- let mut _6: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:+0:18: +0:18
- let mut _7: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +3:6
- let mut _8: u32; // in scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +3:6
+fn main::{closure#0}(_1: *mut [generator@$DIR/generator_drop_cleanup.rs:10:15: 10:17]) -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/generator_drop_cleanup.rs:+0:15: +3:6
+ let mut _2: (); // in scope 0 at $DIR/generator_drop_cleanup.rs:+0:15: +3:6
+ let _3: std::string::String; // in scope 0 at $DIR/generator_drop_cleanup.rs:+1:13: +1:15
+ let _4: (); // in scope 0 at $DIR/generator_drop_cleanup.rs:+2:9: +2:14
+ let mut _5: (); // in scope 0 at $DIR/generator_drop_cleanup.rs:+2:9: +2:14
+ let mut _6: (); // in scope 0 at $DIR/generator_drop_cleanup.rs:+0:18: +0:18
+ let mut _7: (); // in scope 0 at $DIR/generator_drop_cleanup.rs:+0:15: +3:6
+ let mut _8: u32; // in scope 0 at $DIR/generator_drop_cleanup.rs:+0:15: +3:6
scope 1 {
- debug _s => (((*_1) as variant#3).0: std::string::String); // in scope 1 at $DIR/generator-drop-cleanup.rs:+1:13: +1:15
+ debug _s => (((*_1) as variant#3).0: std::string::String); // in scope 1 at $DIR/generator_drop_cleanup.rs:+1:13: +1:15
}
bb0: {
- _8 = discriminant((*_1)); // scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +3:6
- switchInt(move _8) -> [0_u32: bb7, 3_u32: bb10, otherwise: bb11]; // scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +3:6
+ _8 = discriminant((*_1)); // scope 0 at $DIR/generator_drop_cleanup.rs:+0:15: +3:6
+ switchInt(move _8) -> [0_u32: bb7, 3_u32: bb10, otherwise: bb11]; // scope 0 at $DIR/generator_drop_cleanup.rs:+0:15: +3:6
}
bb1: {
- StorageDead(_5); // scope 1 at $DIR/generator-drop-cleanup.rs:+2:13: +2:14
- StorageDead(_4); // scope 1 at $DIR/generator-drop-cleanup.rs:+2:14: +2:15
- drop((((*_1) as variant#3).0: std::string::String)) -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/generator-drop-cleanup.rs:+3:5: +3:6
+ StorageDead(_5); // scope 1 at $DIR/generator_drop_cleanup.rs:+2:13: +2:14
+ StorageDead(_4); // scope 1 at $DIR/generator_drop_cleanup.rs:+2:14: +2:15
+ drop((((*_1) as variant#3).0: std::string::String)) -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/generator_drop_cleanup.rs:+3:5: +3:6
}
bb2: {
- nop; // scope 0 at $DIR/generator-drop-cleanup.rs:+3:5: +3:6
- goto -> bb8; // scope 0 at $DIR/generator-drop-cleanup.rs:+3:5: +3:6
+ nop; // scope 0 at $DIR/generator_drop_cleanup.rs:+3:5: +3:6
+ goto -> bb8; // scope 0 at $DIR/generator_drop_cleanup.rs:+3:5: +3:6
}
bb3: {
- return; // scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +3:6
+ return; // scope 0 at $DIR/generator_drop_cleanup.rs:+0:15: +3:6
}
bb4 (cleanup): {
- resume; // scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +3:6
+ resume; // scope 0 at $DIR/generator_drop_cleanup.rs:+0:15: +3:6
}
bb5 (cleanup): {
- nop; // scope 0 at $DIR/generator-drop-cleanup.rs:+3:5: +3:6
- goto -> bb4; // scope 0 at $DIR/generator-drop-cleanup.rs:+3:5: +3:6
+ nop; // scope 0 at $DIR/generator_drop_cleanup.rs:+3:5: +3:6
+ goto -> bb4; // scope 0 at $DIR/generator_drop_cleanup.rs:+3:5: +3:6
}
bb6: {
- return; // scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +3:6
+ return; // scope 0 at $DIR/generator_drop_cleanup.rs:+0:15: +3:6
}
bb7: {
- goto -> bb9; // scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +3:6
+ goto -> bb9; // scope 0 at $DIR/generator_drop_cleanup.rs:+0:15: +3:6
}
bb8: {
- goto -> bb3; // scope 0 at $DIR/generator-drop-cleanup.rs:+3:5: +3:6
+ goto -> bb3; // scope 0 at $DIR/generator_drop_cleanup.rs:+3:5: +3:6
}
bb9: {
- goto -> bb6; // scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +3:6
+ goto -> bb6; // scope 0 at $DIR/generator_drop_cleanup.rs:+0:15: +3:6
}
bb10: {
- StorageLive(_4); // scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +3:6
- StorageLive(_5); // scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +3:6
- goto -> bb1; // scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +3:6
+ StorageLive(_4); // scope 0 at $DIR/generator_drop_cleanup.rs:+0:15: +3:6
+ StorageLive(_5); // scope 0 at $DIR/generator_drop_cleanup.rs:+0:15: +3:6
+ goto -> bb1; // scope 0 at $DIR/generator_drop_cleanup.rs:+0:15: +3:6
}
bb11: {
- return; // scope 0 at $DIR/generator-drop-cleanup.rs:+0:15: +3:6
+ return; // scope 0 at $DIR/generator_drop_cleanup.rs:+0:15: +3:6
}
}
--- /dev/null
+#![feature(generators, generator_trait)]
+
+// ignore-wasm32-bare compiled with panic=abort by default
+
+// Regression test for #58892, generator drop shims should not have blocks
+// spuriously marked as cleanup
+
+// EMIT_MIR generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir
+fn main() {
+ let gen = || {
+ let _s = String::new();
+ yield;
+ };
+}
// MIR for `main::{closure#0}` before StateTransform
-fn main::{closure#0}(_1: [generator@$DIR/generator-storage-dead-unwind.rs:22:16: 22:18], _2: ()) -> ()
+fn main::{closure#0}(_1: [generator@$DIR/generator_storage_dead_unwind.rs:22:16: 22:18], _2: ()) -> ()
yields ()
{
- let mut _0: (); // return place in scope 0 at $DIR/generator-storage-dead-unwind.rs:+0:19: +0:19
- let _3: Foo; // in scope 0 at $DIR/generator-storage-dead-unwind.rs:+1:13: +1:14
- let _5: (); // in scope 0 at $DIR/generator-storage-dead-unwind.rs:+3:9: +3:14
- let mut _6: (); // in scope 0 at $DIR/generator-storage-dead-unwind.rs:+3:9: +3:14
- let _7: (); // in scope 0 at $DIR/generator-storage-dead-unwind.rs:+4:9: +4:16
- let mut _8: Foo; // in scope 0 at $DIR/generator-storage-dead-unwind.rs:+4:14: +4:15
- let _9: (); // in scope 0 at $DIR/generator-storage-dead-unwind.rs:+5:9: +5:16
- let mut _10: Bar; // in scope 0 at $DIR/generator-storage-dead-unwind.rs:+5:14: +5:15
+ let mut _0: (); // return place in scope 0 at $DIR/generator_storage_dead_unwind.rs:+0:19: +0:19
+ let _3: Foo; // in scope 0 at $DIR/generator_storage_dead_unwind.rs:+1:13: +1:14
+ let _5: (); // in scope 0 at $DIR/generator_storage_dead_unwind.rs:+3:9: +3:14
+ let mut _6: (); // in scope 0 at $DIR/generator_storage_dead_unwind.rs:+3:9: +3:14
+ let _7: (); // in scope 0 at $DIR/generator_storage_dead_unwind.rs:+4:9: +4:16
+ let mut _8: Foo; // in scope 0 at $DIR/generator_storage_dead_unwind.rs:+4:14: +4:15
+ let _9: (); // in scope 0 at $DIR/generator_storage_dead_unwind.rs:+5:9: +5:16
+ let mut _10: Bar; // in scope 0 at $DIR/generator_storage_dead_unwind.rs:+5:14: +5:15
scope 1 {
- debug a => _3; // in scope 1 at $DIR/generator-storage-dead-unwind.rs:+1:13: +1:14
- let _4: Bar; // in scope 1 at $DIR/generator-storage-dead-unwind.rs:+2:13: +2:14
+ debug a => _3; // in scope 1 at $DIR/generator_storage_dead_unwind.rs:+1:13: +1:14
+ let _4: Bar; // in scope 1 at $DIR/generator_storage_dead_unwind.rs:+2:13: +2:14
scope 2 {
- debug b => _4; // in scope 2 at $DIR/generator-storage-dead-unwind.rs:+2:13: +2:14
+ debug b => _4; // in scope 2 at $DIR/generator_storage_dead_unwind.rs:+2:13: +2:14
}
}
bb0: {
- StorageLive(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:+1:13: +1:14
- _3 = Foo(const 5_i32); // scope 0 at $DIR/generator-storage-dead-unwind.rs:+1:17: +1:23
- StorageLive(_4); // scope 1 at $DIR/generator-storage-dead-unwind.rs:+2:13: +2:14
- _4 = Bar(const 6_i32); // scope 1 at $DIR/generator-storage-dead-unwind.rs:+2:17: +2:23
- StorageLive(_5); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+3:9: +3:14
- StorageLive(_6); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+3:9: +3:14
- _6 = (); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+3:9: +3:14
- _5 = yield(move _6) -> [resume: bb1, drop: bb6]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:+3:9: +3:14
+ StorageLive(_3); // scope 0 at $DIR/generator_storage_dead_unwind.rs:+1:13: +1:14
+ _3 = Foo(const 5_i32); // scope 0 at $DIR/generator_storage_dead_unwind.rs:+1:17: +1:23
+ StorageLive(_4); // scope 1 at $DIR/generator_storage_dead_unwind.rs:+2:13: +2:14
+ _4 = Bar(const 6_i32); // scope 1 at $DIR/generator_storage_dead_unwind.rs:+2:17: +2:23
+ StorageLive(_5); // scope 2 at $DIR/generator_storage_dead_unwind.rs:+3:9: +3:14
+ StorageLive(_6); // scope 2 at $DIR/generator_storage_dead_unwind.rs:+3:9: +3:14
+ _6 = (); // scope 2 at $DIR/generator_storage_dead_unwind.rs:+3:9: +3:14
+ _5 = yield(move _6) -> [resume: bb1, drop: bb6]; // scope 2 at $DIR/generator_storage_dead_unwind.rs:+3:9: +3:14
}
bb1: {
- StorageDead(_6); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+3:13: +3:14
- StorageDead(_5); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+3:14: +3:15
- StorageLive(_7); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+4:9: +4:16
- StorageLive(_8); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+4:14: +4:15
- _8 = move _3; // scope 2 at $DIR/generator-storage-dead-unwind.rs:+4:14: +4:15
- _7 = take::<Foo>(move _8) -> [return: bb2, unwind: bb10]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:+4:9: +4:16
+ StorageDead(_6); // scope 2 at $DIR/generator_storage_dead_unwind.rs:+3:13: +3:14
+ StorageDead(_5); // scope 2 at $DIR/generator_storage_dead_unwind.rs:+3:14: +3:15
+ StorageLive(_7); // scope 2 at $DIR/generator_storage_dead_unwind.rs:+4:9: +4:16
+ StorageLive(_8); // scope 2 at $DIR/generator_storage_dead_unwind.rs:+4:14: +4:15
+ _8 = move _3; // scope 2 at $DIR/generator_storage_dead_unwind.rs:+4:14: +4:15
+ _7 = take::<Foo>(move _8) -> [return: bb2, unwind: bb10]; // scope 2 at $DIR/generator_storage_dead_unwind.rs:+4:9: +4:16
// mir::Constant
- // + span: $DIR/generator-storage-dead-unwind.rs:26:9: 26:13
+ // + span: $DIR/generator_storage_dead_unwind.rs:26:9: 26:13
// + literal: Const { ty: fn(Foo) {take::<Foo>}, val: Value(<ZST>) }
}
bb2: {
- StorageDead(_8); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+4:15: +4:16
- StorageDead(_7); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+4:16: +4:17
- StorageLive(_9); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+5:9: +5:16
- StorageLive(_10); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+5:14: +5:15
- _10 = move _4; // scope 2 at $DIR/generator-storage-dead-unwind.rs:+5:14: +5:15
- _9 = take::<Bar>(move _10) -> [return: bb3, unwind: bb9]; // scope 2 at $DIR/generator-storage-dead-unwind.rs:+5:9: +5:16
+ StorageDead(_8); // scope 2 at $DIR/generator_storage_dead_unwind.rs:+4:15: +4:16
+ StorageDead(_7); // scope 2 at $DIR/generator_storage_dead_unwind.rs:+4:16: +4:17
+ StorageLive(_9); // scope 2 at $DIR/generator_storage_dead_unwind.rs:+5:9: +5:16
+ StorageLive(_10); // scope 2 at $DIR/generator_storage_dead_unwind.rs:+5:14: +5:15
+ _10 = move _4; // scope 2 at $DIR/generator_storage_dead_unwind.rs:+5:14: +5:15
+ _9 = take::<Bar>(move _10) -> [return: bb3, unwind: bb9]; // scope 2 at $DIR/generator_storage_dead_unwind.rs:+5:9: +5:16
// mir::Constant
- // + span: $DIR/generator-storage-dead-unwind.rs:27:9: 27:13
+ // + span: $DIR/generator_storage_dead_unwind.rs:27:9: 27:13
// + literal: Const { ty: fn(Bar) {take::<Bar>}, val: Value(<ZST>) }
}
bb3: {
- StorageDead(_10); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+5:15: +5:16
- StorageDead(_9); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+5:16: +5:17
- _0 = const (); // scope 0 at $DIR/generator-storage-dead-unwind.rs:+0:19: +6:6
- StorageDead(_4); // scope 1 at $DIR/generator-storage-dead-unwind.rs:+6:5: +6:6
- goto -> bb4; // scope 0 at $DIR/generator-storage-dead-unwind.rs:+6:5: +6:6
+ StorageDead(_10); // scope 2 at $DIR/generator_storage_dead_unwind.rs:+5:15: +5:16
+ StorageDead(_9); // scope 2 at $DIR/generator_storage_dead_unwind.rs:+5:16: +5:17
+ _0 = const (); // scope 0 at $DIR/generator_storage_dead_unwind.rs:+0:19: +6:6
+ StorageDead(_4); // scope 1 at $DIR/generator_storage_dead_unwind.rs:+6:5: +6:6
+ goto -> bb4; // scope 0 at $DIR/generator_storage_dead_unwind.rs:+6:5: +6:6
}
bb4: {
- StorageDead(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:+6:5: +6:6
- drop(_1) -> [return: bb5, unwind: bb14]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:+6:5: +6:6
+ StorageDead(_3); // scope 0 at $DIR/generator_storage_dead_unwind.rs:+6:5: +6:6
+ drop(_1) -> [return: bb5, unwind: bb14]; // scope 0 at $DIR/generator_storage_dead_unwind.rs:+6:5: +6:6
}
bb5: {
- return; // scope 0 at $DIR/generator-storage-dead-unwind.rs:+6:6: +6:6
+ return; // scope 0 at $DIR/generator_storage_dead_unwind.rs:+6:6: +6:6
}
bb6: {
- StorageDead(_6); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+3:13: +3:14
- StorageDead(_5); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+3:14: +3:15
- StorageDead(_4); // scope 1 at $DIR/generator-storage-dead-unwind.rs:+6:5: +6:6
- drop(_3) -> [return: bb7, unwind: bb15]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:+6:5: +6:6
+ StorageDead(_6); // scope 2 at $DIR/generator_storage_dead_unwind.rs:+3:13: +3:14
+ StorageDead(_5); // scope 2 at $DIR/generator_storage_dead_unwind.rs:+3:14: +3:15
+ StorageDead(_4); // scope 1 at $DIR/generator_storage_dead_unwind.rs:+6:5: +6:6
+ drop(_3) -> [return: bb7, unwind: bb15]; // scope 0 at $DIR/generator_storage_dead_unwind.rs:+6:5: +6:6
}
bb7: {
- StorageDead(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:+6:5: +6:6
- drop(_1) -> [return: bb8, unwind: bb14]; // scope 0 at $DIR/generator-storage-dead-unwind.rs:+6:5: +6:6
+ StorageDead(_3); // scope 0 at $DIR/generator_storage_dead_unwind.rs:+6:5: +6:6
+ drop(_1) -> [return: bb8, unwind: bb14]; // scope 0 at $DIR/generator_storage_dead_unwind.rs:+6:5: +6:6
}
bb8: {
- generator_drop; // scope 0 at $DIR/generator-storage-dead-unwind.rs:+0:16: +6:6
+ generator_drop; // scope 0 at $DIR/generator_storage_dead_unwind.rs:+0:16: +6:6
}
bb9 (cleanup): {
- StorageDead(_10); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+5:15: +5:16
- StorageDead(_9); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+5:16: +5:17
+ StorageDead(_10); // scope 2 at $DIR/generator_storage_dead_unwind.rs:+5:15: +5:16
+ StorageDead(_9); // scope 2 at $DIR/generator_storage_dead_unwind.rs:+5:16: +5:17
goto -> bb12; // scope 2 at no-location
}
bb10 (cleanup): {
- goto -> bb11; // scope 2 at $DIR/generator-storage-dead-unwind.rs:+4:15: +4:16
+ goto -> bb11; // scope 2 at $DIR/generator_storage_dead_unwind.rs:+4:15: +4:16
}
bb11 (cleanup): {
- StorageDead(_8); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+4:15: +4:16
- StorageDead(_7); // scope 2 at $DIR/generator-storage-dead-unwind.rs:+4:16: +4:17
+ StorageDead(_8); // scope 2 at $DIR/generator_storage_dead_unwind.rs:+4:15: +4:16
+ StorageDead(_7); // scope 2 at $DIR/generator_storage_dead_unwind.rs:+4:16: +4:17
goto -> bb12; // scope 2 at no-location
}
bb12 (cleanup): {
- StorageDead(_4); // scope 1 at $DIR/generator-storage-dead-unwind.rs:+6:5: +6:6
- goto -> bb13; // scope 0 at $DIR/generator-storage-dead-unwind.rs:+6:5: +6:6
+ StorageDead(_4); // scope 1 at $DIR/generator_storage_dead_unwind.rs:+6:5: +6:6
+ goto -> bb13; // scope 0 at $DIR/generator_storage_dead_unwind.rs:+6:5: +6:6
}
bb13 (cleanup): {
- StorageDead(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:+6:5: +6:6
- drop(_1) -> bb14; // scope 0 at $DIR/generator-storage-dead-unwind.rs:+6:5: +6:6
+ StorageDead(_3); // scope 0 at $DIR/generator_storage_dead_unwind.rs:+6:5: +6:6
+ drop(_1) -> bb14; // scope 0 at $DIR/generator_storage_dead_unwind.rs:+6:5: +6:6
}
bb14 (cleanup): {
- resume; // scope 0 at $DIR/generator-storage-dead-unwind.rs:+0:16: +6:6
+ resume; // scope 0 at $DIR/generator_storage_dead_unwind.rs:+0:16: +6:6
}
bb15 (cleanup): {
- StorageDead(_3); // scope 0 at $DIR/generator-storage-dead-unwind.rs:+6:5: +6:6
- drop(_1) -> bb14; // scope 0 at $DIR/generator-storage-dead-unwind.rs:+6:5: +6:6
+ StorageDead(_3); // scope 0 at $DIR/generator_storage_dead_unwind.rs:+6:5: +6:6
+ drop(_1) -> bb14; // scope 0 at $DIR/generator_storage_dead_unwind.rs:+6:5: +6:6
}
}
--- /dev/null
+// ignore-wasm32-bare compiled with panic=abort by default
+
+// Test that we generate StorageDead on unwind paths for generators.
+//
+// Basic block and local names can safely change, but the StorageDead statements
+// should not go away.
+
+#![feature(generators, generator_trait)]
+
+struct Foo(i32);
+
+impl Drop for Foo {
+ fn drop(&mut self) {}
+}
+
+struct Bar(i32);
+
+fn take<T>(_x: T) {}
+
+// EMIT_MIR generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir
+fn main() {
+ let _gen = || {
+ let a = Foo(5);
+ let b = Bar(6);
+ yield;
+ take(a);
+ take(b);
+ };
+}
},
} */
-fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 19:24]>, _2: u8) -> GeneratorState<(), ()> {
- debug _x => _10; // in scope 0 at $DIR/generator-tiny.rs:+0:17: +0:19
- let mut _0: std::ops::GeneratorState<(), ()>; // return place in scope 0 at $DIR/generator-tiny.rs:+0:16: +6:6
- let _3: HasDrop; // in scope 0 at $DIR/generator-tiny.rs:+1:13: +1:15
- let mut _4: !; // in scope 0 at $DIR/generator-tiny.rs:+2:9: +5:10
- let mut _5: (); // in scope 0 at $DIR/generator-tiny.rs:+0:16: +6:6
- let _6: u8; // in scope 0 at $DIR/generator-tiny.rs:+3:13: +3:18
- let mut _7: (); // in scope 0 at $DIR/generator-tiny.rs:+3:13: +3:18
- let _8: (); // in scope 0 at $DIR/generator-tiny.rs:+4:13: +4:21
- let mut _9: (); // in scope 0 at $DIR/generator-tiny.rs:+0:25: +0:25
- let _10: u8; // in scope 0 at $DIR/generator-tiny.rs:+0:17: +0:19
- let mut _11: u32; // in scope 0 at $DIR/generator-tiny.rs:+0:16: +6:6
+fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator_tiny.rs:19:16: 19:24]>, _2: u8) -> GeneratorState<(), ()> {
+ debug _x => _10; // in scope 0 at $DIR/generator_tiny.rs:+0:17: +0:19
+ let mut _0: std::ops::GeneratorState<(), ()>; // return place in scope 0 at $DIR/generator_tiny.rs:+0:16: +6:6
+ let _3: HasDrop; // in scope 0 at $DIR/generator_tiny.rs:+1:13: +1:15
+ let mut _4: !; // in scope 0 at $DIR/generator_tiny.rs:+2:9: +5:10
+ let mut _5: (); // in scope 0 at $DIR/generator_tiny.rs:+0:16: +6:6
+ let _6: u8; // in scope 0 at $DIR/generator_tiny.rs:+3:13: +3:18
+ let mut _7: (); // in scope 0 at $DIR/generator_tiny.rs:+3:13: +3:18
+ let _8: (); // in scope 0 at $DIR/generator_tiny.rs:+4:13: +4:21
+ let mut _9: (); // in scope 0 at $DIR/generator_tiny.rs:+0:25: +0:25
+ let _10: u8; // in scope 0 at $DIR/generator_tiny.rs:+0:17: +0:19
+ let mut _11: u32; // in scope 0 at $DIR/generator_tiny.rs:+0:16: +6:6
scope 1 {
- debug _d => (((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 19:24])) as variant#3).0: HasDrop); // in scope 1 at $DIR/generator-tiny.rs:+1:13: +1:15
+ debug _d => (((*(_1.0: &mut [generator@$DIR/generator_tiny.rs:19:16: 19:24])) as variant#3).0: HasDrop); // in scope 1 at $DIR/generator_tiny.rs:+1:13: +1:15
}
bb0: {
- _11 = discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 19:24]))); // scope 0 at $DIR/generator-tiny.rs:+0:16: +6:6
- switchInt(move _11) -> [0_u32: bb1, 3_u32: bb5, otherwise: bb6]; // scope 0 at $DIR/generator-tiny.rs:+0:16: +6:6
+ _11 = discriminant((*(_1.0: &mut [generator@$DIR/generator_tiny.rs:19:16: 19:24]))); // scope 0 at $DIR/generator_tiny.rs:+0:16: +6:6
+ switchInt(move _11) -> [0_u32: bb1, 3_u32: bb5, otherwise: bb6]; // scope 0 at $DIR/generator_tiny.rs:+0:16: +6:6
}
bb1: {
- _10 = move _2; // scope 0 at $DIR/generator-tiny.rs:+0:16: +6:6
- nop; // scope 0 at $DIR/generator-tiny.rs:+1:13: +1:15
- (((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 19:24])) as variant#3).0: HasDrop) = HasDrop; // scope 0 at $DIR/generator-tiny.rs:+1:18: +1:25
- StorageLive(_4); // scope 1 at $DIR/generator-tiny.rs:+2:9: +5:10
- goto -> bb2; // scope 1 at $DIR/generator-tiny.rs:+2:9: +5:10
+ _10 = move _2; // scope 0 at $DIR/generator_tiny.rs:+0:16: +6:6
+ nop; // scope 0 at $DIR/generator_tiny.rs:+1:13: +1:15
+ (((*(_1.0: &mut [generator@$DIR/generator_tiny.rs:19:16: 19:24])) as variant#3).0: HasDrop) = HasDrop; // scope 0 at $DIR/generator_tiny.rs:+1:18: +1:25
+ StorageLive(_4); // scope 1 at $DIR/generator_tiny.rs:+2:9: +5:10
+ goto -> bb2; // scope 1 at $DIR/generator_tiny.rs:+2:9: +5:10
}
bb2: {
- StorageLive(_6); // scope 1 at $DIR/generator-tiny.rs:+3:13: +3:18
- StorageLive(_7); // scope 1 at $DIR/generator-tiny.rs:+3:13: +3:18
- _7 = (); // scope 1 at $DIR/generator-tiny.rs:+3:13: +3:18
- Deinit(_0); // scope 1 at $DIR/generator-tiny.rs:+3:13: +3:18
- ((_0 as Yielded).0: ()) = move _7; // scope 1 at $DIR/generator-tiny.rs:+3:13: +3:18
- discriminant(_0) = 0; // scope 1 at $DIR/generator-tiny.rs:+3:13: +3:18
- discriminant((*(_1.0: &mut [generator@$DIR/generator-tiny.rs:19:16: 19:24]))) = 3; // scope 1 at $DIR/generator-tiny.rs:+3:13: +3:18
- return; // scope 1 at $DIR/generator-tiny.rs:+3:13: +3:18
+ StorageLive(_6); // scope 1 at $DIR/generator_tiny.rs:+3:13: +3:18
+ StorageLive(_7); // scope 1 at $DIR/generator_tiny.rs:+3:13: +3:18
+ _7 = (); // scope 1 at $DIR/generator_tiny.rs:+3:13: +3:18
+ Deinit(_0); // scope 1 at $DIR/generator_tiny.rs:+3:13: +3:18
+ ((_0 as Yielded).0: ()) = move _7; // scope 1 at $DIR/generator_tiny.rs:+3:13: +3:18
+ discriminant(_0) = 0; // scope 1 at $DIR/generator_tiny.rs:+3:13: +3:18
+ discriminant((*(_1.0: &mut [generator@$DIR/generator_tiny.rs:19:16: 19:24]))) = 3; // scope 1 at $DIR/generator_tiny.rs:+3:13: +3:18
+ return; // scope 1 at $DIR/generator_tiny.rs:+3:13: +3:18
}
bb3: {
- StorageDead(_7); // scope 1 at $DIR/generator-tiny.rs:+3:17: +3:18
- StorageDead(_6); // scope 1 at $DIR/generator-tiny.rs:+3:18: +3:19
- StorageLive(_8); // scope 1 at $DIR/generator-tiny.rs:+4:13: +4:21
- _8 = callee() -> bb4; // scope 1 at $DIR/generator-tiny.rs:+4:13: +4:21
+ StorageDead(_7); // scope 1 at $DIR/generator_tiny.rs:+3:17: +3:18
+ StorageDead(_6); // scope 1 at $DIR/generator_tiny.rs:+3:18: +3:19
+ StorageLive(_8); // scope 1 at $DIR/generator_tiny.rs:+4:13: +4:21
+ _8 = callee() -> bb4; // scope 1 at $DIR/generator_tiny.rs:+4:13: +4:21
// mir::Constant
- // + span: $DIR/generator-tiny.rs:23:13: 23:19
+ // + span: $DIR/generator_tiny.rs:23:13: 23:19
// + literal: Const { ty: fn() {callee}, val: Value(<ZST>) }
}
bb4: {
- StorageDead(_8); // scope 1 at $DIR/generator-tiny.rs:+4:21: +4:22
- _5 = const (); // scope 1 at $DIR/generator-tiny.rs:+2:14: +5:10
- goto -> bb2; // scope 1 at $DIR/generator-tiny.rs:+2:9: +5:10
+ StorageDead(_8); // scope 1 at $DIR/generator_tiny.rs:+4:21: +4:22
+ _5 = const (); // scope 1 at $DIR/generator_tiny.rs:+2:14: +5:10
+ goto -> bb2; // scope 1 at $DIR/generator_tiny.rs:+2:9: +5:10
}
bb5: {
- StorageLive(_4); // scope 0 at $DIR/generator-tiny.rs:+0:16: +6:6
- StorageLive(_6); // scope 0 at $DIR/generator-tiny.rs:+0:16: +6:6
- StorageLive(_7); // scope 0 at $DIR/generator-tiny.rs:+0:16: +6:6
- _6 = move _2; // scope 0 at $DIR/generator-tiny.rs:+0:16: +6:6
- goto -> bb3; // scope 0 at $DIR/generator-tiny.rs:+0:16: +6:6
+ StorageLive(_4); // scope 0 at $DIR/generator_tiny.rs:+0:16: +6:6
+ StorageLive(_6); // scope 0 at $DIR/generator_tiny.rs:+0:16: +6:6
+ StorageLive(_7); // scope 0 at $DIR/generator_tiny.rs:+0:16: +6:6
+ _6 = move _2; // scope 0 at $DIR/generator_tiny.rs:+0:16: +6:6
+ goto -> bb3; // scope 0 at $DIR/generator_tiny.rs:+0:16: +6:6
}
bb6: {
- unreachable; // scope 0 at $DIR/generator-tiny.rs:+0:16: +6:6
+ unreachable; // scope 0 at $DIR/generator_tiny.rs:+0:16: +6:6
}
}
--- /dev/null
+//! Tests that generators that cannot return or unwind don't have unnecessary
+//! panic branches.
+
+// compile-flags: -C panic=abort
+// no-prefer-dynamic
+
+#![feature(generators, generator_trait)]
+
+struct HasDrop;
+
+impl Drop for HasDrop {
+ fn drop(&mut self) {}
+}
+
+fn callee() {}
+
+// EMIT_MIR generator_tiny.main-{closure#0}.generator_resume.0.mir
+fn main() {
+ let _gen = |_x: u8| {
+ let _d = HasDrop;
+ loop {
+ yield;
+ callee();
+ }
+ };
+}
--- /dev/null
+digraph Mir_0_3 {
+ graph [fontname="Courier, monospace"];
+ node [fontname="Courier, monospace"];
+ edge [fontname="Courier, monospace"];
+ label=<fn main() -> ()<br align="left"/>>;
+ bb0__0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">0</td></tr><tr><td align="left" balign="left">_0 = const ()<br/></td></tr><tr><td align="left">return</td></tr></table>>];
+}
+++ /dev/null
-digraph Mir_0_3 {
- graph [fontname="Courier, monospace"];
- node [fontname="Courier, monospace"];
- edge [fontname="Courier, monospace"];
- label=<fn main() -> ()<br align="left"/>>;
- bb0__0_3 [shape="none", label=<<table border="0" cellborder="1" cellspacing="0"><tr><td bgcolor="gray" align="center" colspan="1">0</td></tr><tr><td align="left" balign="left">_0 = const ()<br/></td></tr><tr><td align="left">return</td></tr></table>>];
-}
// Test graphviz output
// compile-flags: -Z dump-mir-graphviz
-// EMIT_MIR graphviz.main.mir_map.0.dot
+// EMIT_MIR graphviz.main.built.after.dot
fn main() {}
+++ /dev/null
-// unit-test: SimplifyComparisonIntegral
-// EMIT_MIR if_condition_int.opt_u32.SimplifyComparisonIntegral.diff
-// EMIT_MIR if_condition_int.opt_negative.SimplifyComparisonIntegral.diff
-// EMIT_MIR if_condition_int.opt_char.SimplifyComparisonIntegral.diff
-// EMIT_MIR if_condition_int.opt_i8.SimplifyComparisonIntegral.diff
-// EMIT_MIR if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff
-// EMIT_MIR if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff
-// EMIT_MIR if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff
-// EMIT_MIR if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff
-
-fn opt_u32(x: u32) -> u32 {
- if x == 42 { 0 } else { 1 }
-}
-
-// don't opt: it is already optimal to switch on the bool
-fn dont_opt_bool(x: bool) -> u32 {
- if x { 0 } else { 1 }
-}
-
-fn opt_char(x: char) -> u32 {
- if x == 'x' { 0 } else { 1 }
-}
-
-fn opt_i8(x: i8) -> u32 {
- if x == 42 { 0 } else { 1 }
-}
-
-fn opt_negative(x: i32) -> u32 {
- if x == -42 { 0 } else { 1 }
-}
-
-fn opt_multiple_ifs(x: u32) -> u32 {
- if x == 42 {
- 0
- } else if x != 21 {
- 1
- } else {
- 2
- }
-}
-
-// test that we optimize, but do not remove the b statement, as that is used later on
-fn dont_remove_comparison(a: i8) -> i32 {
- let b = a == 17;
- match b {
- false => 10 + b as i32,
- true => 100 + b as i32,
- }
-}
-
-// test that we do not optimize on floats
-fn dont_opt_floats(a: f32) -> i32 {
- if a == -42.0 { 0 } else { 1 }
-}
-
-fn main() {
- opt_u32(0);
- opt_char('0');
- opt_i8(22);
- dont_opt_bool(false);
- opt_negative(0);
- opt_multiple_ifs(0);
- dont_remove_comparison(11);
- dont_opt_floats(1.0);
-}
+ // MIR for `dont_opt_bool` after SimplifyComparisonIntegral
fn dont_opt_bool(_1: bool) -> u32 {
- debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:+0:18: +0:19
- let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:+0:30: +0:33
- let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9
+ debug x => _1; // in scope 0 at $DIR/if_condition_int.rs:+0:18: +0:19
+ let mut _0: u32; // return place in scope 0 at $DIR/if_condition_int.rs:+0:30: +0:33
+ let mut _2: bool; // in scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
bb0: {
- StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9
- _2 = _1; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9
- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9
+ StorageLive(_2); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
+ _2 = _1; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
+ switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
}
bb1: {
- _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:+1:12: +1:13
- goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:+1:5: +1:26
+ _0 = const 0_u32; // scope 0 at $DIR/if_condition_int.rs:+1:12: +1:13
+ goto -> bb3; // scope 0 at $DIR/if_condition_int.rs:+1:5: +1:26
}
bb2: {
- _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:+1:23: +1:24
- goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:+1:5: +1:26
+ _0 = const 1_u32; // scope 0 at $DIR/if_condition_int.rs:+1:23: +1:24
+ goto -> bb3; // scope 0 at $DIR/if_condition_int.rs:+1:5: +1:26
}
bb3: {
- StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:+1:25: +1:26
- return; // scope 0 at $DIR/if-condition-int.rs:+2:2: +2:2
+ StorageDead(_2); // scope 0 at $DIR/if_condition_int.rs:+1:25: +1:26
+ return; // scope 0 at $DIR/if_condition_int.rs:+2:2: +2:2
}
}
+ // MIR for `dont_opt_floats` after SimplifyComparisonIntegral
fn dont_opt_floats(_1: f32) -> i32 {
- debug a => _1; // in scope 0 at $DIR/if-condition-int.rs:+0:20: +0:21
- let mut _0: i32; // return place in scope 0 at $DIR/if-condition-int.rs:+0:31: +0:34
- let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:+1:8: +1:18
- let mut _3: f32; // in scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9
+ debug a => _1; // in scope 0 at $DIR/if_condition_int.rs:+0:20: +0:21
+ let mut _0: i32; // return place in scope 0 at $DIR/if_condition_int.rs:+0:31: +0:34
+ let mut _2: bool; // in scope 0 at $DIR/if_condition_int.rs:+1:8: +1:18
+ let mut _3: f32; // in scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
bb0: {
- StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:18
- StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9
- _3 = _1; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9
- _2 = Eq(move _3, const -42f32); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:18
- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:17: +1:18
- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:18
+ StorageLive(_2); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:18
+ StorageLive(_3); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
+ _3 = _1; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
+ _2 = Eq(move _3, const -42f32); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:18
+ StorageDead(_3); // scope 0 at $DIR/if_condition_int.rs:+1:17: +1:18
+ switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:18
}
bb1: {
- _0 = const 0_i32; // scope 0 at $DIR/if-condition-int.rs:+1:21: +1:22
- goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:+1:5: +1:35
+ _0 = const 0_i32; // scope 0 at $DIR/if_condition_int.rs:+1:21: +1:22
+ goto -> bb3; // scope 0 at $DIR/if_condition_int.rs:+1:5: +1:35
}
bb2: {
- _0 = const 1_i32; // scope 0 at $DIR/if-condition-int.rs:+1:32: +1:33
- goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:+1:5: +1:35
+ _0 = const 1_i32; // scope 0 at $DIR/if_condition_int.rs:+1:32: +1:33
+ goto -> bb3; // scope 0 at $DIR/if_condition_int.rs:+1:5: +1:35
}
bb3: {
- StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:+1:34: +1:35
- return; // scope 0 at $DIR/if-condition-int.rs:+2:2: +2:2
+ StorageDead(_2); // scope 0 at $DIR/if_condition_int.rs:+1:34: +1:35
+ return; // scope 0 at $DIR/if_condition_int.rs:+2:2: +2:2
}
}
+ // MIR for `dont_remove_comparison` after SimplifyComparisonIntegral
fn dont_remove_comparison(_1: i8) -> i32 {
- debug a => _1; // in scope 0 at $DIR/if-condition-int.rs:+0:27: +0:28
- let mut _0: i32; // return place in scope 0 at $DIR/if-condition-int.rs:+0:37: +0:40
- let _2: bool; // in scope 0 at $DIR/if-condition-int.rs:+1:9: +1:10
- let mut _3: i8; // in scope 0 at $DIR/if-condition-int.rs:+1:13: +1:14
- let mut _4: i32; // in scope 0 at $DIR/if-condition-int.rs:+3:23: +3:31
- let mut _5: bool; // in scope 0 at $DIR/if-condition-int.rs:+3:23: +3:24
- let mut _6: i32; // in scope 0 at $DIR/if-condition-int.rs:+4:23: +4:31
- let mut _7: bool; // in scope 0 at $DIR/if-condition-int.rs:+4:23: +4:24
+ debug a => _1; // in scope 0 at $DIR/if_condition_int.rs:+0:27: +0:28
+ let mut _0: i32; // return place in scope 0 at $DIR/if_condition_int.rs:+0:37: +0:40
+ let _2: bool; // in scope 0 at $DIR/if_condition_int.rs:+1:9: +1:10
+ let mut _3: i8; // in scope 0 at $DIR/if_condition_int.rs:+1:13: +1:14
+ let mut _4: i32; // in scope 0 at $DIR/if_condition_int.rs:+3:23: +3:31
+ let mut _5: bool; // in scope 0 at $DIR/if_condition_int.rs:+3:23: +3:24
+ let mut _6: i32; // in scope 0 at $DIR/if_condition_int.rs:+4:23: +4:31
+ let mut _7: bool; // in scope 0 at $DIR/if_condition_int.rs:+4:23: +4:24
scope 1 {
- debug b => _2; // in scope 1 at $DIR/if-condition-int.rs:+1:9: +1:10
+ debug b => _2; // in scope 1 at $DIR/if_condition_int.rs:+1:9: +1:10
}
bb0: {
- StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:+1:9: +1:10
- StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:+1:13: +1:14
- _3 = _1; // scope 0 at $DIR/if-condition-int.rs:+1:13: +1:14
-- _2 = Eq(move _3, const 17_i8); // scope 0 at $DIR/if-condition-int.rs:+1:13: +1:20
-- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:19: +1:20
-- switchInt(_2) -> [false: bb2, otherwise: bb1]; // scope 1 at $DIR/if-condition-int.rs:+2:5: +2:12
-+ _2 = Eq(_3, const 17_i8); // scope 0 at $DIR/if-condition-int.rs:+1:13: +1:20
-+ nop; // scope 0 at $DIR/if-condition-int.rs:+1:19: +1:20
-+ switchInt(move _3) -> [17_i8: bb1, otherwise: bb2]; // scope 1 at $DIR/if-condition-int.rs:+2:5: +2:12
+ StorageLive(_2); // scope 0 at $DIR/if_condition_int.rs:+1:9: +1:10
+ StorageLive(_3); // scope 0 at $DIR/if_condition_int.rs:+1:13: +1:14
+ _3 = _1; // scope 0 at $DIR/if_condition_int.rs:+1:13: +1:14
+- _2 = Eq(move _3, const 17_i8); // scope 0 at $DIR/if_condition_int.rs:+1:13: +1:20
+- StorageDead(_3); // scope 0 at $DIR/if_condition_int.rs:+1:19: +1:20
+- switchInt(_2) -> [false: bb2, otherwise: bb1]; // scope 1 at $DIR/if_condition_int.rs:+2:5: +2:12
++ _2 = Eq(_3, const 17_i8); // scope 0 at $DIR/if_condition_int.rs:+1:13: +1:20
++ nop; // scope 0 at $DIR/if_condition_int.rs:+1:19: +1:20
++ switchInt(move _3) -> [17_i8: bb1, otherwise: bb2]; // scope 1 at $DIR/if_condition_int.rs:+2:5: +2:12
}
bb1: {
-+ StorageDead(_3); // scope 1 at $DIR/if-condition-int.rs:+2:5: +2:12
- StorageLive(_6); // scope 1 at $DIR/if-condition-int.rs:+4:23: +4:31
- StorageLive(_7); // scope 1 at $DIR/if-condition-int.rs:+4:23: +4:24
- _7 = _2; // scope 1 at $DIR/if-condition-int.rs:+4:23: +4:24
- _6 = move _7 as i32 (IntToInt); // scope 1 at $DIR/if-condition-int.rs:+4:23: +4:31
- StorageDead(_7); // scope 1 at $DIR/if-condition-int.rs:+4:30: +4:31
- _0 = Add(const 100_i32, move _6); // scope 1 at $DIR/if-condition-int.rs:+4:17: +4:31
- StorageDead(_6); // scope 1 at $DIR/if-condition-int.rs:+4:30: +4:31
- goto -> bb3; // scope 1 at $DIR/if-condition-int.rs:+4:30: +4:31
++ StorageDead(_3); // scope 1 at $DIR/if_condition_int.rs:+2:5: +2:12
+ StorageLive(_6); // scope 1 at $DIR/if_condition_int.rs:+4:23: +4:31
+ StorageLive(_7); // scope 1 at $DIR/if_condition_int.rs:+4:23: +4:24
+ _7 = _2; // scope 1 at $DIR/if_condition_int.rs:+4:23: +4:24
+ _6 = move _7 as i32 (IntToInt); // scope 1 at $DIR/if_condition_int.rs:+4:23: +4:31
+ StorageDead(_7); // scope 1 at $DIR/if_condition_int.rs:+4:30: +4:31
+ _0 = Add(const 100_i32, move _6); // scope 1 at $DIR/if_condition_int.rs:+4:17: +4:31
+ StorageDead(_6); // scope 1 at $DIR/if_condition_int.rs:+4:30: +4:31
+ goto -> bb3; // scope 1 at $DIR/if_condition_int.rs:+4:30: +4:31
}
bb2: {
-+ StorageDead(_3); // scope 1 at $DIR/if-condition-int.rs:+2:5: +2:12
- StorageLive(_4); // scope 1 at $DIR/if-condition-int.rs:+3:23: +3:31
- StorageLive(_5); // scope 1 at $DIR/if-condition-int.rs:+3:23: +3:24
- _5 = _2; // scope 1 at $DIR/if-condition-int.rs:+3:23: +3:24
- _4 = move _5 as i32 (IntToInt); // scope 1 at $DIR/if-condition-int.rs:+3:23: +3:31
- StorageDead(_5); // scope 1 at $DIR/if-condition-int.rs:+3:30: +3:31
- _0 = Add(const 10_i32, move _4); // scope 1 at $DIR/if-condition-int.rs:+3:18: +3:31
- StorageDead(_4); // scope 1 at $DIR/if-condition-int.rs:+3:30: +3:31
- goto -> bb3; // scope 1 at $DIR/if-condition-int.rs:+3:30: +3:31
++ StorageDead(_3); // scope 1 at $DIR/if_condition_int.rs:+2:5: +2:12
+ StorageLive(_4); // scope 1 at $DIR/if_condition_int.rs:+3:23: +3:31
+ StorageLive(_5); // scope 1 at $DIR/if_condition_int.rs:+3:23: +3:24
+ _5 = _2; // scope 1 at $DIR/if_condition_int.rs:+3:23: +3:24
+ _4 = move _5 as i32 (IntToInt); // scope 1 at $DIR/if_condition_int.rs:+3:23: +3:31
+ StorageDead(_5); // scope 1 at $DIR/if_condition_int.rs:+3:30: +3:31
+ _0 = Add(const 10_i32, move _4); // scope 1 at $DIR/if_condition_int.rs:+3:18: +3:31
+ StorageDead(_4); // scope 1 at $DIR/if_condition_int.rs:+3:30: +3:31
+ goto -> bb3; // scope 1 at $DIR/if_condition_int.rs:+3:30: +3:31
}
bb3: {
- StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:+6:1: +6:2
- return; // scope 0 at $DIR/if-condition-int.rs:+6:2: +6:2
+ StorageDead(_2); // scope 0 at $DIR/if_condition_int.rs:+6:1: +6:2
+ return; // scope 0 at $DIR/if_condition_int.rs:+6:2: +6:2
}
}
+ // MIR for `opt_char` after SimplifyComparisonIntegral
fn opt_char(_1: char) -> u32 {
- debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:+0:13: +0:14
- let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:+0:25: +0:28
- let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16
- let mut _3: char; // in scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9
+ debug x => _1; // in scope 0 at $DIR/if_condition_int.rs:+0:13: +0:14
+ let mut _0: u32; // return place in scope 0 at $DIR/if_condition_int.rs:+0:25: +0:28
+ let mut _2: bool; // in scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
+ let mut _3: char; // in scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
bb0: {
- StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16
- StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9
- _3 = _1; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9
-- _2 = Eq(move _3, const 'x'); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16
-- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:15: +1:16
-- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16
-+ nop; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16
-+ nop; // scope 0 at $DIR/if-condition-int.rs:+1:15: +1:16
-+ switchInt(move _3) -> ['x': bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16
+ StorageLive(_2); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
+ StorageLive(_3); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
+ _3 = _1; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
+- _2 = Eq(move _3, const 'x'); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
+- StorageDead(_3); // scope 0 at $DIR/if_condition_int.rs:+1:15: +1:16
+- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
++ nop; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
++ nop; // scope 0 at $DIR/if_condition_int.rs:+1:15: +1:16
++ switchInt(move _3) -> ['x': bb1, otherwise: bb2]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
}
bb1: {
-+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16
- _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:+1:19: +1:20
- goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:+1:5: +1:33
++ StorageDead(_3); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
+ _0 = const 0_u32; // scope 0 at $DIR/if_condition_int.rs:+1:19: +1:20
+ goto -> bb3; // scope 0 at $DIR/if_condition_int.rs:+1:5: +1:33
}
bb2: {
-+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16
- _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:+1:30: +1:31
- goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:+1:5: +1:33
++ StorageDead(_3); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
+ _0 = const 1_u32; // scope 0 at $DIR/if_condition_int.rs:+1:30: +1:31
+ goto -> bb3; // scope 0 at $DIR/if_condition_int.rs:+1:5: +1:33
}
bb3: {
- StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:+1:32: +1:33
- return; // scope 0 at $DIR/if-condition-int.rs:+2:2: +2:2
+ StorageDead(_2); // scope 0 at $DIR/if_condition_int.rs:+1:32: +1:33
+ return; // scope 0 at $DIR/if_condition_int.rs:+2:2: +2:2
}
}
+ // MIR for `opt_i8` after SimplifyComparisonIntegral
fn opt_i8(_1: i8) -> u32 {
- debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:+0:11: +0:12
- let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:+0:21: +0:24
- let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15
- let mut _3: i8; // in scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9
+ debug x => _1; // in scope 0 at $DIR/if_condition_int.rs:+0:11: +0:12
+ let mut _0: u32; // return place in scope 0 at $DIR/if_condition_int.rs:+0:21: +0:24
+ let mut _2: bool; // in scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
+ let mut _3: i8; // in scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
bb0: {
- StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15
- StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9
- _3 = _1; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9
-- _2 = Eq(move _3, const 42_i8); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15
-- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:14: +1:15
-- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15
-+ nop; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15
-+ nop; // scope 0 at $DIR/if-condition-int.rs:+1:14: +1:15
-+ switchInt(move _3) -> [42_i8: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15
+ StorageLive(_2); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
+ StorageLive(_3); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
+ _3 = _1; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
+- _2 = Eq(move _3, const 42_i8); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
+- StorageDead(_3); // scope 0 at $DIR/if_condition_int.rs:+1:14: +1:15
+- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
++ nop; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
++ nop; // scope 0 at $DIR/if_condition_int.rs:+1:14: +1:15
++ switchInt(move _3) -> [42_i8: bb1, otherwise: bb2]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
}
bb1: {
-+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15
- _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:+1:18: +1:19
- goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:+1:5: +1:32
++ StorageDead(_3); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
+ _0 = const 0_u32; // scope 0 at $DIR/if_condition_int.rs:+1:18: +1:19
+ goto -> bb3; // scope 0 at $DIR/if_condition_int.rs:+1:5: +1:32
}
bb2: {
-+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15
- _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:+1:29: +1:30
- goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:+1:5: +1:32
++ StorageDead(_3); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
+ _0 = const 1_u32; // scope 0 at $DIR/if_condition_int.rs:+1:29: +1:30
+ goto -> bb3; // scope 0 at $DIR/if_condition_int.rs:+1:5: +1:32
}
bb3: {
- StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:+1:31: +1:32
- return; // scope 0 at $DIR/if-condition-int.rs:+2:2: +2:2
+ StorageDead(_2); // scope 0 at $DIR/if_condition_int.rs:+1:31: +1:32
+ return; // scope 0 at $DIR/if_condition_int.rs:+2:2: +2:2
}
}
+ // MIR for `opt_multiple_ifs` after SimplifyComparisonIntegral
fn opt_multiple_ifs(_1: u32) -> u32 {
- debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:+0:21: +0:22
- let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:+0:32: +0:35
- let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15
- let mut _3: u32; // in scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9
- let mut _4: bool; // in scope 0 at $DIR/if-condition-int.rs:+3:15: +3:22
- let mut _5: u32; // in scope 0 at $DIR/if-condition-int.rs:+3:15: +3:16
+ debug x => _1; // in scope 0 at $DIR/if_condition_int.rs:+0:21: +0:22
+ let mut _0: u32; // return place in scope 0 at $DIR/if_condition_int.rs:+0:32: +0:35
+ let mut _2: bool; // in scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
+ let mut _3: u32; // in scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
+ let mut _4: bool; // in scope 0 at $DIR/if_condition_int.rs:+3:15: +3:22
+ let mut _5: u32; // in scope 0 at $DIR/if_condition_int.rs:+3:15: +3:16
bb0: {
- StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15
- StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9
- _3 = _1; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9
-- _2 = Eq(move _3, const 42_u32); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15
-- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:14: +1:15
-- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15
-+ nop; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15
-+ nop; // scope 0 at $DIR/if-condition-int.rs:+1:14: +1:15
-+ switchInt(move _3) -> [42_u32: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15
+ StorageLive(_2); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
+ StorageLive(_3); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
+ _3 = _1; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
+- _2 = Eq(move _3, const 42_u32); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
+- StorageDead(_3); // scope 0 at $DIR/if_condition_int.rs:+1:14: +1:15
+- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
++ nop; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
++ nop; // scope 0 at $DIR/if_condition_int.rs:+1:14: +1:15
++ switchInt(move _3) -> [42_u32: bb1, otherwise: bb2]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
}
bb1: {
-+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15
- _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:+2:9: +2:10
- goto -> bb6; // scope 0 at $DIR/if-condition-int.rs:+1:5: +7:6
++ StorageDead(_3); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
+ _0 = const 0_u32; // scope 0 at $DIR/if_condition_int.rs:+2:9: +2:10
+ goto -> bb6; // scope 0 at $DIR/if_condition_int.rs:+1:5: +7:6
}
bb2: {
-+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15
- StorageLive(_4); // scope 0 at $DIR/if-condition-int.rs:+3:15: +3:22
- StorageLive(_5); // scope 0 at $DIR/if-condition-int.rs:+3:15: +3:16
- _5 = _1; // scope 0 at $DIR/if-condition-int.rs:+3:15: +3:16
-- _4 = Ne(move _5, const 21_u32); // scope 0 at $DIR/if-condition-int.rs:+3:15: +3:22
-- StorageDead(_5); // scope 0 at $DIR/if-condition-int.rs:+3:21: +3:22
-- switchInt(move _4) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/if-condition-int.rs:+3:15: +3:22
-+ nop; // scope 0 at $DIR/if-condition-int.rs:+3:15: +3:22
-+ nop; // scope 0 at $DIR/if-condition-int.rs:+3:21: +3:22
-+ switchInt(move _5) -> [21_u32: bb4, otherwise: bb3]; // scope 0 at $DIR/if-condition-int.rs:+3:15: +3:22
++ StorageDead(_3); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
+ StorageLive(_4); // scope 0 at $DIR/if_condition_int.rs:+3:15: +3:22
+ StorageLive(_5); // scope 0 at $DIR/if_condition_int.rs:+3:15: +3:16
+ _5 = _1; // scope 0 at $DIR/if_condition_int.rs:+3:15: +3:16
+- _4 = Ne(move _5, const 21_u32); // scope 0 at $DIR/if_condition_int.rs:+3:15: +3:22
+- StorageDead(_5); // scope 0 at $DIR/if_condition_int.rs:+3:21: +3:22
+- switchInt(move _4) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/if_condition_int.rs:+3:15: +3:22
++ nop; // scope 0 at $DIR/if_condition_int.rs:+3:15: +3:22
++ nop; // scope 0 at $DIR/if_condition_int.rs:+3:21: +3:22
++ switchInt(move _5) -> [21_u32: bb4, otherwise: bb3]; // scope 0 at $DIR/if_condition_int.rs:+3:15: +3:22
}
bb3: {
-+ StorageDead(_5); // scope 0 at $DIR/if-condition-int.rs:+3:15: +3:22
- _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:+4:9: +4:10
- goto -> bb5; // scope 0 at $DIR/if-condition-int.rs:+3:12: +7:6
++ StorageDead(_5); // scope 0 at $DIR/if_condition_int.rs:+3:15: +3:22
+ _0 = const 1_u32; // scope 0 at $DIR/if_condition_int.rs:+4:9: +4:10
+ goto -> bb5; // scope 0 at $DIR/if_condition_int.rs:+3:12: +7:6
}
bb4: {
-+ StorageDead(_5); // scope 0 at $DIR/if-condition-int.rs:+3:15: +3:22
- _0 = const 2_u32; // scope 0 at $DIR/if-condition-int.rs:+6:9: +6:10
- goto -> bb5; // scope 0 at $DIR/if-condition-int.rs:+3:12: +7:6
++ StorageDead(_5); // scope 0 at $DIR/if_condition_int.rs:+3:15: +3:22
+ _0 = const 2_u32; // scope 0 at $DIR/if_condition_int.rs:+6:9: +6:10
+ goto -> bb5; // scope 0 at $DIR/if_condition_int.rs:+3:12: +7:6
}
bb5: {
- StorageDead(_4); // scope 0 at $DIR/if-condition-int.rs:+7:5: +7:6
- goto -> bb6; // scope 0 at $DIR/if-condition-int.rs:+1:5: +7:6
+ StorageDead(_4); // scope 0 at $DIR/if_condition_int.rs:+7:5: +7:6
+ goto -> bb6; // scope 0 at $DIR/if_condition_int.rs:+1:5: +7:6
}
bb6: {
- StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:+7:5: +7:6
- return; // scope 0 at $DIR/if-condition-int.rs:+8:2: +8:2
+ StorageDead(_2); // scope 0 at $DIR/if_condition_int.rs:+7:5: +7:6
+ return; // scope 0 at $DIR/if_condition_int.rs:+8:2: +8:2
}
}
+ // MIR for `opt_negative` after SimplifyComparisonIntegral
fn opt_negative(_1: i32) -> u32 {
- debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:+0:17: +0:18
- let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:+0:28: +0:31
- let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16
- let mut _3: i32; // in scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9
+ debug x => _1; // in scope 0 at $DIR/if_condition_int.rs:+0:17: +0:18
+ let mut _0: u32; // return place in scope 0 at $DIR/if_condition_int.rs:+0:28: +0:31
+ let mut _2: bool; // in scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
+ let mut _3: i32; // in scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
bb0: {
- StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16
- StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9
- _3 = _1; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9
-- _2 = Eq(move _3, const -42_i32); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16
-- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:15: +1:16
-- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16
-+ nop; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16
-+ nop; // scope 0 at $DIR/if-condition-int.rs:+1:15: +1:16
-+ switchInt(move _3) -> [-42_i32: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16
+ StorageLive(_2); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
+ StorageLive(_3); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
+ _3 = _1; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
+- _2 = Eq(move _3, const -42_i32); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
+- StorageDead(_3); // scope 0 at $DIR/if_condition_int.rs:+1:15: +1:16
+- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
++ nop; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
++ nop; // scope 0 at $DIR/if_condition_int.rs:+1:15: +1:16
++ switchInt(move _3) -> [-42_i32: bb1, otherwise: bb2]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
}
bb1: {
-+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16
- _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:+1:19: +1:20
- goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:+1:5: +1:33
++ StorageDead(_3); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
+ _0 = const 0_u32; // scope 0 at $DIR/if_condition_int.rs:+1:19: +1:20
+ goto -> bb3; // scope 0 at $DIR/if_condition_int.rs:+1:5: +1:33
}
bb2: {
-+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:16
- _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:+1:30: +1:31
- goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:+1:5: +1:33
++ StorageDead(_3); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:16
+ _0 = const 1_u32; // scope 0 at $DIR/if_condition_int.rs:+1:30: +1:31
+ goto -> bb3; // scope 0 at $DIR/if_condition_int.rs:+1:5: +1:33
}
bb3: {
- StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:+1:32: +1:33
- return; // scope 0 at $DIR/if-condition-int.rs:+2:2: +2:2
+ StorageDead(_2); // scope 0 at $DIR/if_condition_int.rs:+1:32: +1:33
+ return; // scope 0 at $DIR/if_condition_int.rs:+2:2: +2:2
}
}
+ // MIR for `opt_u32` after SimplifyComparisonIntegral
fn opt_u32(_1: u32) -> u32 {
- debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:+0:12: +0:13
- let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:+0:23: +0:26
- let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15
- let mut _3: u32; // in scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9
+ debug x => _1; // in scope 0 at $DIR/if_condition_int.rs:+0:12: +0:13
+ let mut _0: u32; // return place in scope 0 at $DIR/if_condition_int.rs:+0:23: +0:26
+ let mut _2: bool; // in scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
+ let mut _3: u32; // in scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
bb0: {
- StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15
- StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9
- _3 = _1; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:9
-- _2 = Eq(move _3, const 42_u32); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15
-- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:14: +1:15
-- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15
-+ nop; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15
-+ nop; // scope 0 at $DIR/if-condition-int.rs:+1:14: +1:15
-+ switchInt(move _3) -> [42_u32: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15
+ StorageLive(_2); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
+ StorageLive(_3); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
+ _3 = _1; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:9
+- _2 = Eq(move _3, const 42_u32); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
+- StorageDead(_3); // scope 0 at $DIR/if_condition_int.rs:+1:14: +1:15
+- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
++ nop; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
++ nop; // scope 0 at $DIR/if_condition_int.rs:+1:14: +1:15
++ switchInt(move _3) -> [42_u32: bb1, otherwise: bb2]; // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
}
bb1: {
-+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15
- _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:+1:18: +1:19
- goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:+1:5: +1:32
++ StorageDead(_3); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
+ _0 = const 0_u32; // scope 0 at $DIR/if_condition_int.rs:+1:18: +1:19
+ goto -> bb3; // scope 0 at $DIR/if_condition_int.rs:+1:5: +1:32
}
bb2: {
-+ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:+1:8: +1:15
- _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:+1:29: +1:30
- goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:+1:5: +1:32
++ StorageDead(_3); // scope 0 at $DIR/if_condition_int.rs:+1:8: +1:15
+ _0 = const 1_u32; // scope 0 at $DIR/if_condition_int.rs:+1:29: +1:30
+ goto -> bb3; // scope 0 at $DIR/if_condition_int.rs:+1:5: +1:32
}
bb3: {
- StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:+1:31: +1:32
- return; // scope 0 at $DIR/if-condition-int.rs:+2:2: +2:2
+ StorageDead(_2); // scope 0 at $DIR/if_condition_int.rs:+1:31: +1:32
+ return; // scope 0 at $DIR/if_condition_int.rs:+2:2: +2:2
}
}
--- /dev/null
+// unit-test: SimplifyComparisonIntegral
+// EMIT_MIR if_condition_int.opt_u32.SimplifyComparisonIntegral.diff
+// EMIT_MIR if_condition_int.opt_negative.SimplifyComparisonIntegral.diff
+// EMIT_MIR if_condition_int.opt_char.SimplifyComparisonIntegral.diff
+// EMIT_MIR if_condition_int.opt_i8.SimplifyComparisonIntegral.diff
+// EMIT_MIR if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff
+// EMIT_MIR if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff
+// EMIT_MIR if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff
+// EMIT_MIR if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff
+
+fn opt_u32(x: u32) -> u32 {
+ if x == 42 { 0 } else { 1 }
+}
+
+// don't opt: it is already optimal to switch on the bool
+fn dont_opt_bool(x: bool) -> u32 {
+ if x { 0 } else { 1 }
+}
+
+fn opt_char(x: char) -> u32 {
+ if x == 'x' { 0 } else { 1 }
+}
+
+fn opt_i8(x: i8) -> u32 {
+ if x == 42 { 0 } else { 1 }
+}
+
+fn opt_negative(x: i32) -> u32 {
+ if x == -42 { 0 } else { 1 }
+}
+
+fn opt_multiple_ifs(x: u32) -> u32 {
+ if x == 42 {
+ 0
+ } else if x != 21 {
+ 1
+ } else {
+ 2
+ }
+}
+
+// test that we optimize, but do not remove the b statement, as that is used later on
+fn dont_remove_comparison(a: i8) -> i32 {
+ let b = a == 17;
+ match b {
+ false => 10 + b as i32,
+ true => 100 + b as i32,
+ }
+}
+
+// test that we do not optimize on floats
+fn dont_opt_floats(a: f32) -> i32 {
+ if a == -42.0 { 0 } else { 1 }
+}
+
+fn main() {
+ opt_u32(0);
+ opt_char('0');
+ opt_i8(22);
+ dont_opt_bool(false);
+ opt_negative(0);
+ opt_multiple_ifs(0);
+ dont_remove_comparison(11);
+ dont_opt_floats(1.0);
+}
+++ /dev/null
-// Tests inlining of `may_unwind` inline assembly.
-//
-// ignore-wasm32-bare compiled with panic=abort by default
-// needs-asm-support
-#![feature(asm_unwind)]
-
-struct D;
-
-impl Drop for D {
- fn drop(&mut self) {}
-}
-
-#[inline(always)]
-fn foo() {
- let _d = D;
- unsafe { std::arch::asm!("", options(may_unwind)) };
-}
-
-// EMIT_MIR asm_unwind.main.Inline.diff
-pub fn main() {
- foo();
-}
+ // MIR for `main` after Inline
fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/asm-unwind.rs:+0:15: +0:15
- let _1: (); // in scope 0 at $DIR/asm-unwind.rs:+1:5: +1:10
-+ scope 1 (inlined foo) { // at $DIR/asm-unwind.rs:21:5: 21:10
-+ let _2: D; // in scope 1 at $DIR/asm-unwind.rs:15:9: 15:11
+ let mut _0: (); // return place in scope 0 at $DIR/asm_unwind.rs:+0:15: +0:15
+ let _1: (); // in scope 0 at $DIR/asm_unwind.rs:+1:5: +1:10
++ scope 1 (inlined foo) { // at $DIR/asm_unwind.rs:21:5: 21:10
++ let _2: D; // in scope 1 at $DIR/asm_unwind.rs:15:9: 15:11
+ scope 2 {
-+ debug _d => _2; // in scope 2 at $DIR/asm-unwind.rs:15:9: 15:11
++ debug _d => _2; // in scope 2 at $DIR/asm_unwind.rs:15:9: 15:11
+ scope 3 {
+ }
+ }
+ }
bb0: {
- StorageLive(_1); // scope 0 at $DIR/asm-unwind.rs:+1:5: +1:10
-- _1 = foo() -> bb1; // scope 0 at $DIR/asm-unwind.rs:+1:5: +1:10
+ StorageLive(_1); // scope 0 at $DIR/asm_unwind.rs:+1:5: +1:10
+- _1 = foo() -> bb1; // scope 0 at $DIR/asm_unwind.rs:+1:5: +1:10
- // mir::Constant
-- // + span: $DIR/asm-unwind.rs:21:5: 21:8
+- // + span: $DIR/asm_unwind.rs:21:5: 21:8
- // + literal: Const { ty: fn() {foo}, val: Value(<ZST>) }
-+ StorageLive(_2); // scope 1 at $DIR/asm-unwind.rs:15:9: 15:11
-+ asm!("", options(MAY_UNWIND)) -> [return: bb1, unwind: bb3]; // scope 3 at $DIR/asm-unwind.rs:16:14: 16:54
++ StorageLive(_2); // scope 1 at $DIR/asm_unwind.rs:15:9: 15:11
++ asm!("", options(MAY_UNWIND)) -> [return: bb1, unwind: bb3]; // scope 3 at $DIR/asm_unwind.rs:16:14: 16:54
}
bb1: {
-+ drop(_2) -> bb2; // scope 1 at $DIR/asm-unwind.rs:17:1: 17:2
++ drop(_2) -> bb2; // scope 1 at $DIR/asm_unwind.rs:17:1: 17:2
+ }
+
+ bb2: {
-+ StorageDead(_2); // scope 1 at $DIR/asm-unwind.rs:17:1: 17:2
- StorageDead(_1); // scope 0 at $DIR/asm-unwind.rs:+1:10: +1:11
- _0 = const (); // scope 0 at $DIR/asm-unwind.rs:+0:15: +2:2
- return; // scope 0 at $DIR/asm-unwind.rs:+2:2: +2:2
++ StorageDead(_2); // scope 1 at $DIR/asm_unwind.rs:17:1: 17:2
+ StorageDead(_1); // scope 0 at $DIR/asm_unwind.rs:+1:10: +1:11
+ _0 = const (); // scope 0 at $DIR/asm_unwind.rs:+0:15: +2:2
+ return; // scope 0 at $DIR/asm_unwind.rs:+2:2: +2:2
+ }
+
+ bb3 (cleanup): {
-+ drop(_2) -> bb4; // scope 1 at $DIR/asm-unwind.rs:17:1: 17:2
++ drop(_2) -> bb4; // scope 1 at $DIR/asm_unwind.rs:17:1: 17:2
+ }
+
+ bb4 (cleanup): {
-+ resume; // scope 1 at $DIR/asm-unwind.rs:14:1: 17:2
++ resume; // scope 1 at $DIR/asm_unwind.rs:14:1: 17:2
}
}
--- /dev/null
+// Tests inlining of `may_unwind` inline assembly.
+//
+// ignore-wasm32-bare compiled with panic=abort by default
+// needs-asm-support
+#![feature(asm_unwind)]
+
+struct D;
+
+impl Drop for D {
+ fn drop(&mut self) {}
+}
+
+#[inline(always)]
+fn foo() {
+ let _d = D;
+ unsafe { std::arch::asm!("", options(may_unwind)) };
+}
+
+// EMIT_MIR asm_unwind.main.Inline.diff
+pub fn main() {
+ foo();
+}
+++ /dev/null
-// ignore-wasm32 compiled with panic=abort by default
-// needs-unwind
-
-#![crate_type = "lib"]
-pub trait Factory<T> {
- type Item;
-}
-
-pub struct IntFactory;
-
-impl<T> Factory<T> for IntFactory {
- type Item = usize;
-}
-
-// EMIT_MIR caller_with_trivial_bound.foo.Inline.diff
-pub fn foo<T>()
-where
- IntFactory: Factory<T>,
-{
- let mut x: <IntFactory as Factory<T>>::Item = bar::<T>();
-}
-
-#[inline(always)]
-pub fn bar<T>() -> <IntFactory as Factory<T>>::Item {
- 0usize
-}
+ // MIR for `foo` after Inline
fn foo() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/caller-with-trivial-bound.rs:+1:1: +1:1
- let mut _1: <IntFactory as Factory<T>>::Item; // in scope 0 at $DIR/caller-with-trivial-bound.rs:+4:9: +4:14
+ let mut _0: (); // return place in scope 0 at $DIR/caller_with_trivial_bound.rs:+1:1: +1:1
+ let mut _1: <IntFactory as Factory<T>>::Item; // in scope 0 at $DIR/caller_with_trivial_bound.rs:+4:9: +4:14
scope 1 {
- debug x => _1; // in scope 1 at $DIR/caller-with-trivial-bound.rs:+4:9: +4:14
+ debug x => _1; // in scope 1 at $DIR/caller_with_trivial_bound.rs:+4:9: +4:14
}
bb0: {
- StorageLive(_1); // scope 0 at $DIR/caller-with-trivial-bound.rs:+4:9: +4:14
- _1 = bar::<T>() -> bb1; // scope 0 at $DIR/caller-with-trivial-bound.rs:+4:51: +4:61
+ StorageLive(_1); // scope 0 at $DIR/caller_with_trivial_bound.rs:+4:9: +4:14
+ _1 = bar::<T>() -> bb1; // scope 0 at $DIR/caller_with_trivial_bound.rs:+4:51: +4:61
// mir::Constant
- // + span: $DIR/caller-with-trivial-bound.rs:20:51: 20:59
+ // + span: $DIR/caller_with_trivial_bound.rs:20:51: 20:59
// + literal: Const { ty: fn() -> <IntFactory as Factory<T>>::Item {bar::<T>}, val: Value(<ZST>) }
}
bb1: {
- _0 = const (); // scope 0 at $DIR/caller-with-trivial-bound.rs:+3:1: +5:2
- drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/caller-with-trivial-bound.rs:+5:1: +5:2
+ _0 = const (); // scope 0 at $DIR/caller_with_trivial_bound.rs:+3:1: +5:2
+ drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/caller_with_trivial_bound.rs:+5:1: +5:2
}
bb2: {
- StorageDead(_1); // scope 0 at $DIR/caller-with-trivial-bound.rs:+5:1: +5:2
- return; // scope 0 at $DIR/caller-with-trivial-bound.rs:+5:2: +5:2
+ StorageDead(_1); // scope 0 at $DIR/caller_with_trivial_bound.rs:+5:1: +5:2
+ return; // scope 0 at $DIR/caller_with_trivial_bound.rs:+5:2: +5:2
}
bb3 (cleanup): {
- resume; // scope 0 at $DIR/caller-with-trivial-bound.rs:+0:1: +5:2
+ resume; // scope 0 at $DIR/caller_with_trivial_bound.rs:+0:1: +5:2
}
}
--- /dev/null
+// ignore-wasm32 compiled with panic=abort by default
+// needs-unwind
+
+#![crate_type = "lib"]
+pub trait Factory<T> {
+ type Item;
+}
+
+pub struct IntFactory;
+
+impl<T> Factory<T> for IntFactory {
+ type Item = usize;
+}
+
+// EMIT_MIR caller_with_trivial_bound.foo.Inline.diff
+pub fn foo<T>()
+where
+ IntFactory: Factory<T>,
+{
+ let mut x: <IntFactory as Factory<T>>::Item = bar::<T>();
+}
+
+#[inline(always)]
+pub fn bar<T>() -> <IntFactory as Factory<T>>::Item {
+ 0usize
+}
+++ /dev/null
-#![crate_type = "lib"]
-
-use std::fmt::Debug;
-
-pub trait Cache {
- type V: Debug;
-
- fn store_nocache(&self);
-}
-
-pub trait Query {
- type V;
- type C: Cache<V = Self::V>;
-
- fn cache<T>(s: &T) -> &Self::C;
-}
-
-// EMIT_MIR dyn_trait.mk_cycle.Inline.diff
-#[inline(always)]
-pub fn mk_cycle<V: Debug>(c: &dyn Cache<V = V>) {
- c.store_nocache()
-}
-
-// EMIT_MIR dyn_trait.try_execute_query.Inline.diff
-#[inline(always)]
-pub fn try_execute_query<C: Cache>(c: &C) {
- mk_cycle(c)
-}
-
-// EMIT_MIR dyn_trait.get_query.Inline.diff
-#[inline(always)]
-pub fn get_query<Q: Query, T>(t: &T) {
- let c = Q::cache(t);
- try_execute_query(c)
-}
+ // MIR for `get_query` after Inline
fn get_query(_1: &T) -> () {
- debug t => _1; // in scope 0 at $DIR/dyn-trait.rs:+0:31: +0:32
- let mut _0: (); // return place in scope 0 at $DIR/dyn-trait.rs:+0:38: +0:38
- let _2: &<Q as Query>::C; // in scope 0 at $DIR/dyn-trait.rs:+1:9: +1:10
- let mut _3: &T; // in scope 0 at $DIR/dyn-trait.rs:+1:22: +1:23
- let mut _4: &<Q as Query>::C; // in scope 0 at $DIR/dyn-trait.rs:+2:23: +2:24
+ debug t => _1; // in scope 0 at $DIR/dyn_trait.rs:+0:31: +0:32
+ let mut _0: (); // return place in scope 0 at $DIR/dyn_trait.rs:+0:38: +0:38
+ let _2: &<Q as Query>::C; // in scope 0 at $DIR/dyn_trait.rs:+1:9: +1:10
+ let mut _3: &T; // in scope 0 at $DIR/dyn_trait.rs:+1:22: +1:23
+ let mut _4: &<Q as Query>::C; // in scope 0 at $DIR/dyn_trait.rs:+2:23: +2:24
scope 1 {
- debug c => _2; // in scope 1 at $DIR/dyn-trait.rs:+1:9: +1:10
-+ scope 2 (inlined try_execute_query::<<Q as Query>::C>) { // at $DIR/dyn-trait.rs:34:5: 34:25
-+ debug c => _4; // in scope 2 at $DIR/dyn-trait.rs:26:36: 26:37
-+ let mut _5: &dyn Cache<V = <Q as Query>::V>; // in scope 2 at $DIR/dyn-trait.rs:27:14: 27:15
-+ let mut _6: &<Q as Query>::C; // in scope 2 at $DIR/dyn-trait.rs:27:14: 27:15
-+ scope 3 (inlined mk_cycle::<<Q as Query>::V>) { // at $DIR/dyn-trait.rs:27:5: 27:16
-+ debug c => _5; // in scope 3 at $DIR/dyn-trait.rs:20:27: 20:28
-+ let mut _7: &dyn Cache<V = <Q as Query>::V>; // in scope 3 at $DIR/dyn-trait.rs:21:5: 21:22
+ debug c => _2; // in scope 1 at $DIR/dyn_trait.rs:+1:9: +1:10
++ scope 2 (inlined try_execute_query::<<Q as Query>::C>) { // at $DIR/dyn_trait.rs:34:5: 34:25
++ debug c => _4; // in scope 2 at $DIR/dyn_trait.rs:26:36: 26:37
++ let mut _5: &dyn Cache<V = <Q as Query>::V>; // in scope 2 at $DIR/dyn_trait.rs:27:14: 27:15
++ let mut _6: &<Q as Query>::C; // in scope 2 at $DIR/dyn_trait.rs:27:14: 27:15
++ scope 3 (inlined mk_cycle::<<Q as Query>::V>) { // at $DIR/dyn_trait.rs:27:5: 27:16
++ debug c => _5; // in scope 3 at $DIR/dyn_trait.rs:20:27: 20:28
++ let mut _7: &dyn Cache<V = <Q as Query>::V>; // in scope 3 at $DIR/dyn_trait.rs:21:5: 21:22
+ }
+ }
}
bb0: {
- StorageLive(_2); // scope 0 at $DIR/dyn-trait.rs:+1:9: +1:10
- StorageLive(_3); // scope 0 at $DIR/dyn-trait.rs:+1:22: +1:23
- _3 = &(*_1); // scope 0 at $DIR/dyn-trait.rs:+1:22: +1:23
- _2 = <Q as Query>::cache::<T>(move _3) -> bb1; // scope 0 at $DIR/dyn-trait.rs:+1:13: +1:24
+ StorageLive(_2); // scope 0 at $DIR/dyn_trait.rs:+1:9: +1:10
+ StorageLive(_3); // scope 0 at $DIR/dyn_trait.rs:+1:22: +1:23
+ _3 = &(*_1); // scope 0 at $DIR/dyn_trait.rs:+1:22: +1:23
+ _2 = <Q as Query>::cache::<T>(move _3) -> bb1; // scope 0 at $DIR/dyn_trait.rs:+1:13: +1:24
// mir::Constant
- // + span: $DIR/dyn-trait.rs:33:13: 33:21
+ // + span: $DIR/dyn_trait.rs:33:13: 33:21
// + user_ty: UserType(0)
// + literal: Const { ty: for<'a> fn(&'a T) -> &'a <Q as Query>::C {<Q as Query>::cache::<T>}, val: Value(<ZST>) }
}
bb1: {
- StorageDead(_3); // scope 0 at $DIR/dyn-trait.rs:+1:23: +1:24
- StorageLive(_4); // scope 1 at $DIR/dyn-trait.rs:+2:23: +2:24
- _4 = &(*_2); // scope 1 at $DIR/dyn-trait.rs:+2:23: +2:24
-- _0 = try_execute_query::<<Q as Query>::C>(move _4) -> bb2; // scope 1 at $DIR/dyn-trait.rs:+2:5: +2:25
-+ StorageLive(_5); // scope 2 at $DIR/dyn-trait.rs:27:14: 27:15
-+ StorageLive(_6); // scope 2 at $DIR/dyn-trait.rs:27:14: 27:15
-+ _6 = _4; // scope 2 at $DIR/dyn-trait.rs:27:14: 27:15
-+ _5 = move _6 as &dyn Cache<V = <Q as Query>::V> (Pointer(Unsize)); // scope 2 at $DIR/dyn-trait.rs:27:14: 27:15
-+ StorageDead(_6); // scope 2 at $DIR/dyn-trait.rs:27:14: 27:15
-+ StorageLive(_7); // scope 3 at $DIR/dyn-trait.rs:21:5: 21:22
-+ _7 = _5; // scope 3 at $DIR/dyn-trait.rs:21:5: 21:22
-+ _0 = <dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache(move _7) -> bb2; // scope 3 at $DIR/dyn-trait.rs:21:5: 21:22
+ StorageDead(_3); // scope 0 at $DIR/dyn_trait.rs:+1:23: +1:24
+ StorageLive(_4); // scope 1 at $DIR/dyn_trait.rs:+2:23: +2:24
+ _4 = &(*_2); // scope 1 at $DIR/dyn_trait.rs:+2:23: +2:24
+- _0 = try_execute_query::<<Q as Query>::C>(move _4) -> bb2; // scope 1 at $DIR/dyn_trait.rs:+2:5: +2:25
++ StorageLive(_5); // scope 2 at $DIR/dyn_trait.rs:27:14: 27:15
++ StorageLive(_6); // scope 2 at $DIR/dyn_trait.rs:27:14: 27:15
++ _6 = _4; // scope 2 at $DIR/dyn_trait.rs:27:14: 27:15
++ _5 = move _6 as &dyn Cache<V = <Q as Query>::V> (Pointer(Unsize)); // scope 2 at $DIR/dyn_trait.rs:27:14: 27:15
++ StorageDead(_6); // scope 2 at $DIR/dyn_trait.rs:27:14: 27:15
++ StorageLive(_7); // scope 3 at $DIR/dyn_trait.rs:21:5: 21:22
++ _7 = _5; // scope 3 at $DIR/dyn_trait.rs:21:5: 21:22
++ _0 = <dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache(move _7) -> bb2; // scope 3 at $DIR/dyn_trait.rs:21:5: 21:22
// mir::Constant
-- // + span: $DIR/dyn-trait.rs:34:5: 34:22
+- // + span: $DIR/dyn_trait.rs:34:5: 34:22
- // + literal: Const { ty: for<'a> fn(&'a <Q as Query>::C) {try_execute_query::<<Q as Query>::C>}, val: Value(<ZST>) }
-+ // + span: $DIR/dyn-trait.rs:21:7: 21:20
++ // + span: $DIR/dyn_trait.rs:21:7: 21:20
+ // + literal: Const { ty: for<'a> fn(&'a dyn Cache<V = <Q as Query>::V>) {<dyn Cache<V = <Q as Query>::V> as Cache>::store_nocache}, val: Value(<ZST>) }
}
bb2: {
-+ StorageDead(_7); // scope 3 at $DIR/dyn-trait.rs:21:21: 21:22
-+ StorageDead(_5); // scope 2 at $DIR/dyn-trait.rs:27:15: 27:16
- StorageDead(_4); // scope 1 at $DIR/dyn-trait.rs:+2:24: +2:25
- StorageDead(_2); // scope 0 at $DIR/dyn-trait.rs:+3:1: +3:2
- return; // scope 0 at $DIR/dyn-trait.rs:+3:2: +3:2
++ StorageDead(_7); // scope 3 at $DIR/dyn_trait.rs:21:21: 21:22
++ StorageDead(_5); // scope 2 at $DIR/dyn_trait.rs:27:15: 27:16
+ StorageDead(_4); // scope 1 at $DIR/dyn_trait.rs:+2:24: +2:25
+ StorageDead(_2); // scope 0 at $DIR/dyn_trait.rs:+3:1: +3:2
+ return; // scope 0 at $DIR/dyn_trait.rs:+3:2: +3:2
}
}
+ // MIR for `mk_cycle` after Inline
fn mk_cycle(_1: &dyn Cache<V = V>) -> () {
- debug c => _1; // in scope 0 at $DIR/dyn-trait.rs:+0:27: +0:28
- let mut _0: (); // return place in scope 0 at $DIR/dyn-trait.rs:+0:49: +0:49
- let mut _2: &dyn Cache<V = V>; // in scope 0 at $DIR/dyn-trait.rs:+1:5: +1:22
+ debug c => _1; // in scope 0 at $DIR/dyn_trait.rs:+0:27: +0:28
+ let mut _0: (); // return place in scope 0 at $DIR/dyn_trait.rs:+0:49: +0:49
+ let mut _2: &dyn Cache<V = V>; // in scope 0 at $DIR/dyn_trait.rs:+1:5: +1:22
bb0: {
- StorageLive(_2); // scope 0 at $DIR/dyn-trait.rs:+1:5: +1:22
- _2 = &(*_1); // scope 0 at $DIR/dyn-trait.rs:+1:5: +1:22
- _0 = <dyn Cache<V = V> as Cache>::store_nocache(move _2) -> bb1; // scope 0 at $DIR/dyn-trait.rs:+1:5: +1:22
+ StorageLive(_2); // scope 0 at $DIR/dyn_trait.rs:+1:5: +1:22
+ _2 = &(*_1); // scope 0 at $DIR/dyn_trait.rs:+1:5: +1:22
+ _0 = <dyn Cache<V = V> as Cache>::store_nocache(move _2) -> bb1; // scope 0 at $DIR/dyn_trait.rs:+1:5: +1:22
// mir::Constant
- // + span: $DIR/dyn-trait.rs:21:7: 21:20
+ // + span: $DIR/dyn_trait.rs:21:7: 21:20
// + literal: Const { ty: for<'a> fn(&'a dyn Cache<V = V>) {<dyn Cache<V = V> as Cache>::store_nocache}, val: Value(<ZST>) }
}
bb1: {
- StorageDead(_2); // scope 0 at $DIR/dyn-trait.rs:+1:21: +1:22
- return; // scope 0 at $DIR/dyn-trait.rs:+2:2: +2:2
+ StorageDead(_2); // scope 0 at $DIR/dyn_trait.rs:+1:21: +1:22
+ return; // scope 0 at $DIR/dyn_trait.rs:+2:2: +2:2
}
}
--- /dev/null
+#![crate_type = "lib"]
+
+use std::fmt::Debug;
+
+pub trait Cache {
+ type V: Debug;
+
+ fn store_nocache(&self);
+}
+
+pub trait Query {
+ type V;
+ type C: Cache<V = Self::V>;
+
+ fn cache<T>(s: &T) -> &Self::C;
+}
+
+// EMIT_MIR dyn_trait.mk_cycle.Inline.diff
+#[inline(always)]
+pub fn mk_cycle<V: Debug>(c: &dyn Cache<V = V>) {
+ c.store_nocache()
+}
+
+// EMIT_MIR dyn_trait.try_execute_query.Inline.diff
+#[inline(always)]
+pub fn try_execute_query<C: Cache>(c: &C) {
+ mk_cycle(c)
+}
+
+// EMIT_MIR dyn_trait.get_query.Inline.diff
+#[inline(always)]
+pub fn get_query<Q: Query, T>(t: &T) {
+ let c = Q::cache(t);
+ try_execute_query(c)
+}
+ // MIR for `try_execute_query` after Inline
fn try_execute_query(_1: &C) -> () {
- debug c => _1; // in scope 0 at $DIR/dyn-trait.rs:+0:36: +0:37
- let mut _0: (); // return place in scope 0 at $DIR/dyn-trait.rs:+0:43: +0:43
- let mut _2: &dyn Cache<V = <C as Cache>::V>; // in scope 0 at $DIR/dyn-trait.rs:+1:14: +1:15
- let mut _3: &C; // in scope 0 at $DIR/dyn-trait.rs:+1:14: +1:15
-+ scope 1 (inlined mk_cycle::<<C as Cache>::V>) { // at $DIR/dyn-trait.rs:27:5: 27:16
-+ debug c => _2; // in scope 1 at $DIR/dyn-trait.rs:20:27: 20:28
-+ let mut _4: &dyn Cache<V = <C as Cache>::V>; // in scope 1 at $DIR/dyn-trait.rs:21:5: 21:22
+ debug c => _1; // in scope 0 at $DIR/dyn_trait.rs:+0:36: +0:37
+ let mut _0: (); // return place in scope 0 at $DIR/dyn_trait.rs:+0:43: +0:43
+ let mut _2: &dyn Cache<V = <C as Cache>::V>; // in scope 0 at $DIR/dyn_trait.rs:+1:14: +1:15
+ let mut _3: &C; // in scope 0 at $DIR/dyn_trait.rs:+1:14: +1:15
++ scope 1 (inlined mk_cycle::<<C as Cache>::V>) { // at $DIR/dyn_trait.rs:27:5: 27:16
++ debug c => _2; // in scope 1 at $DIR/dyn_trait.rs:20:27: 20:28
++ let mut _4: &dyn Cache<V = <C as Cache>::V>; // in scope 1 at $DIR/dyn_trait.rs:21:5: 21:22
+ }
bb0: {
- StorageLive(_2); // scope 0 at $DIR/dyn-trait.rs:+1:14: +1:15
- StorageLive(_3); // scope 0 at $DIR/dyn-trait.rs:+1:14: +1:15
- _3 = &(*_1); // scope 0 at $DIR/dyn-trait.rs:+1:14: +1:15
- _2 = move _3 as &dyn Cache<V = <C as Cache>::V> (Pointer(Unsize)); // scope 0 at $DIR/dyn-trait.rs:+1:14: +1:15
- StorageDead(_3); // scope 0 at $DIR/dyn-trait.rs:+1:14: +1:15
-- _0 = mk_cycle::<<C as Cache>::V>(move _2) -> bb1; // scope 0 at $DIR/dyn-trait.rs:+1:5: +1:16
-+ StorageLive(_4); // scope 1 at $DIR/dyn-trait.rs:21:5: 21:22
-+ _4 = _2; // scope 1 at $DIR/dyn-trait.rs:21:5: 21:22
-+ _0 = <dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache(move _4) -> bb1; // scope 1 at $DIR/dyn-trait.rs:21:5: 21:22
+ StorageLive(_2); // scope 0 at $DIR/dyn_trait.rs:+1:14: +1:15
+ StorageLive(_3); // scope 0 at $DIR/dyn_trait.rs:+1:14: +1:15
+ _3 = &(*_1); // scope 0 at $DIR/dyn_trait.rs:+1:14: +1:15
+ _2 = move _3 as &dyn Cache<V = <C as Cache>::V> (Pointer(Unsize)); // scope 0 at $DIR/dyn_trait.rs:+1:14: +1:15
+ StorageDead(_3); // scope 0 at $DIR/dyn_trait.rs:+1:14: +1:15
+- _0 = mk_cycle::<<C as Cache>::V>(move _2) -> bb1; // scope 0 at $DIR/dyn_trait.rs:+1:5: +1:16
++ StorageLive(_4); // scope 1 at $DIR/dyn_trait.rs:21:5: 21:22
++ _4 = _2; // scope 1 at $DIR/dyn_trait.rs:21:5: 21:22
++ _0 = <dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache(move _4) -> bb1; // scope 1 at $DIR/dyn_trait.rs:21:5: 21:22
// mir::Constant
-- // + span: $DIR/dyn-trait.rs:27:5: 27:13
+- // + span: $DIR/dyn_trait.rs:27:5: 27:13
- // + literal: Const { ty: for<'a> fn(&'a (dyn Cache<V = <C as Cache>::V> + 'a)) {mk_cycle::<<C as Cache>::V>}, val: Value(<ZST>) }
-+ // + span: $DIR/dyn-trait.rs:21:7: 21:20
++ // + span: $DIR/dyn_trait.rs:21:7: 21:20
+ // + literal: Const { ty: for<'a> fn(&'a dyn Cache<V = <C as Cache>::V>) {<dyn Cache<V = <C as Cache>::V> as Cache>::store_nocache}, val: Value(<ZST>) }
}
bb1: {
-+ StorageDead(_4); // scope 1 at $DIR/dyn-trait.rs:21:21: 21:22
- StorageDead(_2); // scope 0 at $DIR/dyn-trait.rs:+1:15: +1:16
- return; // scope 0 at $DIR/dyn-trait.rs:+2:2: +2:2
++ StorageDead(_4); // scope 1 at $DIR/dyn_trait.rs:21:21: 21:22
+ StorageDead(_2); // scope 0 at $DIR/dyn_trait.rs:+1:15: +1:16
+ return; // scope 0 at $DIR/dyn_trait.rs:+2:2: +2:2
}
}
+++ /dev/null
-// compile-flags: -Z span_free_formats
-
-// Tests that MIR inliner works for any operand
-
-fn main() {
- println!("{}", bar());
-}
-
-// EMIT_MIR inline_any_operand.bar.Inline.after.mir
-fn bar() -> bool {
- let f = foo;
- f(1, -1)
-}
-
-#[inline(always)]
-fn foo(x: i32, y: i32) -> bool {
- x == y
-}
+++ /dev/null
-// Checks that inliner doesn't introduce cycles when optimizing generators.
-// The outcome of optimization is not verfied, just the absence of the cycle.
-// Regression test for #76181.
-//
-// edition:2018
-
-#![crate_type = "lib"]
-
-pub struct S;
-
-impl S {
- pub async fn g(&mut self) {
- self.h();
- }
- pub fn h(&mut self) {
- let _ = self.g();
- }
-}
+++ /dev/null
-// compile-flags: -Z span_free_formats -Zunsound-mir-opts
-
-// Tests that MIR inliner can handle closure arguments,
-// even when (#45894)
-
-fn main() {
- println!("{}", foo(0, &14));
-}
-
-// EMIT_MIR inline_closure_borrows_arg.foo.Inline.after.mir
-fn foo<T: Copy>(_t: T, q: &i32) -> i32 {
- let x = |r: &i32, _s: &i32| {
- let variable = &*r;
- *variable
- };
- x(q, q)
-}
+++ /dev/null
-// compile-flags: -Z span_free_formats
-
-// Tests that MIR inliner can handle closure captures.
-
-fn main() {
- println!("{:?}", foo(0, 14));
-}
-
-// EMIT_MIR inline_closure_captures.foo.Inline.after.mir
-fn foo<T: Copy>(t: T, q: i32) -> (i32, T) {
- let x = |_q| (q, t);
- x(q)
-}
+++ /dev/null
-// compile-flags: -Z span_free_formats
-
-// Tests that MIR inliner can handle closure arguments. (#45894)
-
-fn main() {
- println!("{}", foo(0, 14));
-}
-
-// EMIT_MIR inline_closure.foo.Inline.after.mir
-fn foo<T: Copy>(_t: T, q: i32) -> i32 {
- let x = |_t, _q| _t;
- x(q, q)
-}
+++ /dev/null
-// Checks that only functions with compatible attributes are inlined.
-//
-// only-x86_64
-
-#![crate_type = "lib"]
-#![feature(no_sanitize)]
-#![feature(target_feature_11)]
-#![feature(c_variadic)]
-
-// EMIT_MIR inline_compatibility.inlined_target_feature.Inline.diff
-#[target_feature(enable = "sse2")]
-pub unsafe fn inlined_target_feature() {
- target_feature();
-}
-
-// EMIT_MIR inline_compatibility.not_inlined_target_feature.Inline.diff
-pub unsafe fn not_inlined_target_feature() {
- target_feature();
-}
-
-// EMIT_MIR inline_compatibility.inlined_no_sanitize.Inline.diff
-#[no_sanitize(address)]
-pub unsafe fn inlined_no_sanitize() {
- no_sanitize();
-}
-
-// EMIT_MIR inline_compatibility.not_inlined_no_sanitize.Inline.diff
-pub unsafe fn not_inlined_no_sanitize() {
- no_sanitize();
-}
-
-#[inline]
-#[target_feature(enable = "sse2")]
-pub unsafe fn target_feature() {}
-
-#[inline]
-#[no_sanitize(address)]
-pub unsafe fn no_sanitize() {}
-
-// EMIT_MIR inline_compatibility.not_inlined_c_variadic.Inline.diff
-pub unsafe fn not_inlined_c_variadic() {
- let s = sum(4u32, 4u32, 30u32, 200u32, 1000u32);
-}
-
-#[no_mangle]
-#[inline(always)]
-unsafe extern "C" fn sum(n: u32, mut vs: ...) -> u32 {
- let mut s = 0;
- let mut i = 0;
- while i != n {
- s += vs.arg::<u32>();
- i += 1;
- }
- s
-}
+++ /dev/null
-// Check that inliner handles various forms of recursion and doesn't fall into
-// an infinite inlining cycle. The particular outcome of inlining is not
-// crucial otherwise.
-//
-// Regression test for issue #78573.
-
-// EMIT_MIR inline_cycle_generic.main.Inline.diff
-fn main() {
- <C as Call>::call();
-}
-
-pub trait Call {
- fn call();
-}
-
-pub struct A;
-pub struct B<T>(T);
-pub struct C;
-
-impl Call for A {
- #[inline]
- fn call() {
- <B<C> as Call>::call()
- }
-}
-
-
-impl<T: Call> Call for B<T> {
- #[inline]
- fn call() {
- <T as Call>::call()
- }
-}
-
-impl Call for C {
- #[inline]
- fn call() {
- <B<A> as Call>::call()
- }
-}
+++ /dev/null
-// Check that inliner handles various forms of recursion and doesn't fall into
-// an infinite inlining cycle. The particular outcome of inlining is not
-// crucial otherwise.
-//
-// Regression test for issue #78573.
-
-fn main() {
- one();
- two();
-}
-
-// EMIT_MIR inline_cycle.one.Inline.diff
-fn one() {
- <C as Call>::call();
-}
-
-pub trait Call {
- fn call();
-}
-
-pub struct A<T>(T);
-pub struct B<T>(T);
-pub struct C;
-
-impl<T: Call> Call for A<T> {
- #[inline]
- fn call() {
- <B<T> as Call>::call()
- }
-}
-
-
-impl<T: Call> Call for B<T> {
- #[inline]
- fn call() {
- <T as Call>::call()
- }
-}
-
-impl Call for C {
- #[inline]
- fn call() {
- A::<C>::call()
- }
-}
-
-// EMIT_MIR inline_cycle.two.Inline.diff
-fn two() {
- call(f);
-}
-
-#[inline]
-fn call<F: FnOnce()>(f: F) {
- f();
-}
-
-#[inline]
-fn f() {
- call(f);
-}
+++ /dev/null
-// Tests inlining of diverging calls.
-//
-// ignore-wasm32-bare compiled with panic=abort by default
-#![crate_type = "lib"]
-
-// EMIT_MIR inline_diverging.f.Inline.diff
-pub fn f() {
- sleep();
-}
-
-// EMIT_MIR inline_diverging.g.Inline.diff
-pub fn g(i: i32) -> u32 {
- if i > 0 {
- i as u32
- } else {
- panic();
- }
-}
-
-// EMIT_MIR inline_diverging.h.Inline.diff
-pub fn h() {
- call_twice(sleep);
-}
-
-#[inline(always)]
-pub fn call_twice<R, F: Fn() -> R>(f: F) -> (R, R) {
- let a = f();
- let b = f();
- (a, b)
-}
-
-#[inline(always)]
-fn panic() -> ! {
- panic!();
-}
-
-#[inline(always)]
-fn sleep() -> ! {
- loop {}
-}
+++ /dev/null
-// ignore-wasm32-bare compiled with panic=abort by default
-#![feature(generators, generator_trait)]
-
-use std::ops::Generator;
-use std::pin::Pin;
-
-// EMIT_MIR inline_generator.main.Inline.diff
-fn main() {
- let _r = Pin::new(&mut g()).resume(false);
-}
-
-#[inline(always)]
-pub fn g() -> impl Generator<bool> {
- #[inline(always)]
- |a| { yield if a { 7 } else { 13 } }
-}
+++ /dev/null
-// Checks that only functions with the compatible instruction_set attributes are inlined.
-//
-// compile-flags: --target thumbv4t-none-eabi
-// needs-llvm-components: arm
-
-#![crate_type = "lib"]
-#![feature(rustc_attrs)]
-#![feature(no_core, lang_items)]
-#![feature(isa_attribute)]
-#![no_core]
-
-#[rustc_builtin_macro]
-#[macro_export]
-macro_rules! asm {
- ("assembly template",
- $(operands,)*
- $(options($(option),*))?
- ) => {
- /* compiler built-in */
- };
-}
-
-#[lang = "sized"]
-trait Sized {}
-#[lang = "copy"]
-trait Copy {}
-
-#[instruction_set(arm::a32)]
-#[inline]
-fn instruction_set_a32() {}
-
-#[instruction_set(arm::t32)]
-#[inline]
-fn instruction_set_t32() {}
-
-#[inline]
-fn instruction_set_default() {}
-
-// EMIT_MIR inline_instruction_set.t32.Inline.diff
-#[instruction_set(arm::t32)]
-pub fn t32() {
- instruction_set_a32();
- instruction_set_t32();
- // The default instruction set is currently
- // conservatively assumed to be incompatible.
- instruction_set_default();
-}
-
-// EMIT_MIR inline_instruction_set.default.Inline.diff
-pub fn default() {
- instruction_set_a32();
- instruction_set_t32();
- instruction_set_default();
-}
+++ /dev/null
-// ignore-endian-big
-// ignore-wasm32-bare compiled with panic=abort by default
-// compile-flags: -Z mir-opt-level=4
-
-#![feature(box_syntax)]
-// EMIT_MIR inline_into_box_place.main.Inline.diff
-fn main() {
- let _x: Box<Vec<u32>> = box Vec::new();
-}
+++ /dev/null
-// Checks that inlining threshold can be controlled with
-// inline-mir-threshold and inline-hint-threshold options.
-//
-// compile-flags: -Zinline-mir-threshold=90
-// compile-flags: -Zinline-mir-hint-threshold=50
-
-// EMIT_MIR inline_options.main.Inline.after.mir
-fn main() {
- not_inlined();
- inlined::<u32>();
-}
-
-// Cost is approximately 3 * 25 + 5 = 80.
-#[inline]
-pub fn not_inlined() { g(); g(); g(); }
-pub fn inlined<T>() { g(); g(); g(); }
-
-#[inline(never)]
-fn g() {}
+++ /dev/null
-// compile-flags: -Z span_free_formats -Z mir-emit-retag
-
-// Tests that MIR inliner fixes up `Retag`'s `fn_entry` flag
-
-fn main() {
- println!("{}", bar());
-}
-
-// EMIT_MIR inline_retag.bar.Inline.after.mir
-fn bar() -> bool {
- let f = foo;
- f(&1, &-1)
-}
-
-#[inline(always)]
-fn foo(x: &i32, y: &i32) -> bool {
- *x == *y
-}
+++ /dev/null
-// ignore-wasm32-bare compiled with panic=abort by default
-#![crate_type = "lib"]
-
-// EMIT_MIR inline_shims.clone.Inline.diff
-pub fn clone<A, B>(f: fn(A, B)) -> fn(A, B) {
- f.clone()
-}
-
-// EMIT_MIR inline_shims.drop.Inline.diff
-pub fn drop<A, B>(a: *mut Vec<A>, b: *mut Option<B>) {
- unsafe { std::ptr::drop_in_place(a) }
- unsafe { std::ptr::drop_in_place(b) }
-}
+++ /dev/null
-#![feature(specialization)]
-
-// EMIT_MIR inline_specialization.main.Inline.diff
-fn main() {
- let x = <Vec::<()> as Foo>::bar();
-}
-
-trait Foo {
- fn bar() -> u32;
-}
-
-impl<T> Foo for Vec<T> {
- #[inline(always)]
- default fn bar() -> u32 { 123 }
-}
+++ /dev/null
-// compile-flags: -Z span_free_formats
-
-fn main() {
- println!("{}", test(&()));
-}
-
-// EMIT_MIR inline_trait_method.test.Inline.after.mir
-fn test(x: &dyn X) -> u32 {
- x.y()
-}
-
-trait X {
- fn y(&self) -> u32 {
- 1
- }
-}
-
-impl X for () {
- fn y(&self) -> u32 {
- 2
- }
-}
+++ /dev/null
-// compile-flags: -Z span_free_formats -Z mir-opt-level=4
-
-// EMIT_MIR inline_trait_method_2.test2.Inline.after.mir
-fn test2(x: &dyn X) -> bool {
- test(x)
-}
-
-#[inline]
-fn test(x: &dyn X) -> bool {
- x.y()
-}
-
-trait X {
- fn y(&self) -> bool {
- false
- }
-}
-
-impl X for () {
- fn y(&self) -> bool {
- true
- }
-}
-
-fn main() {
- println!("Should be true: {}", test2(&()));
-}
// MIR for `bar` after Inline
fn bar() -> bool {
- let mut _0: bool; // return place in scope 0 at $DIR/inline-any-operand.rs:+0:13: +0:17
- let _1: fn(i32, i32) -> bool {foo}; // in scope 0 at $DIR/inline-any-operand.rs:+1:9: +1:10
- let mut _2: fn(i32, i32) -> bool {foo}; // in scope 0 at $DIR/inline-any-operand.rs:+2:5: +2:6
- let mut _3: i32; // in scope 0 at $DIR/inline-any-operand.rs:+2:5: +2:13
- let mut _4: i32; // in scope 0 at $DIR/inline-any-operand.rs:+2:5: +2:13
+ let mut _0: bool; // return place in scope 0 at $DIR/inline_any_operand.rs:+0:13: +0:17
+ let _1: fn(i32, i32) -> bool {foo}; // in scope 0 at $DIR/inline_any_operand.rs:+1:9: +1:10
+ let mut _2: fn(i32, i32) -> bool {foo}; // in scope 0 at $DIR/inline_any_operand.rs:+2:5: +2:6
+ let mut _3: i32; // in scope 0 at $DIR/inline_any_operand.rs:+2:5: +2:13
+ let mut _4: i32; // in scope 0 at $DIR/inline_any_operand.rs:+2:5: +2:13
scope 1 {
- debug f => _1; // in scope 1 at $DIR/inline-any-operand.rs:+1:9: +1:10
- scope 2 (inlined foo) { // at $DIR/inline-any-operand.rs:12:5: 12:13
- debug x => _3; // in scope 2 at $DIR/inline-any-operand.rs:16:8: 16:9
- debug y => _4; // in scope 2 at $DIR/inline-any-operand.rs:16:16: 16:17
- let mut _5: i32; // in scope 2 at $DIR/inline-any-operand.rs:17:5: 17:6
- let mut _6: i32; // in scope 2 at $DIR/inline-any-operand.rs:17:10: 17:11
+ debug f => _1; // in scope 1 at $DIR/inline_any_operand.rs:+1:9: +1:10
+ scope 2 (inlined foo) { // at $DIR/inline_any_operand.rs:12:5: 12:13
+ debug x => _3; // in scope 2 at $DIR/inline_any_operand.rs:16:8: 16:9
+ debug y => _4; // in scope 2 at $DIR/inline_any_operand.rs:16:16: 16:17
+ let mut _5: i32; // in scope 2 at $DIR/inline_any_operand.rs:17:5: 17:6
+ let mut _6: i32; // in scope 2 at $DIR/inline_any_operand.rs:17:10: 17:11
}
}
bb0: {
- StorageLive(_1); // scope 0 at $DIR/inline-any-operand.rs:+1:9: +1:10
- _1 = foo; // scope 0 at $DIR/inline-any-operand.rs:+1:13: +1:16
+ StorageLive(_1); // scope 0 at $DIR/inline_any_operand.rs:+1:9: +1:10
+ _1 = foo; // scope 0 at $DIR/inline_any_operand.rs:+1:13: +1:16
// mir::Constant
- // + span: $DIR/inline-any-operand.rs:11:13: 11:16
+ // + span: $DIR/inline_any_operand.rs:11:13: 11:16
// + literal: Const { ty: fn(i32, i32) -> bool {foo}, val: Value(<ZST>) }
- StorageLive(_2); // scope 1 at $DIR/inline-any-operand.rs:+2:5: +2:6
- _2 = _1; // scope 1 at $DIR/inline-any-operand.rs:+2:5: +2:6
- StorageLive(_3); // scope 1 at $DIR/inline-any-operand.rs:+2:5: +2:13
- _3 = const 1_i32; // scope 1 at $DIR/inline-any-operand.rs:+2:5: +2:13
- StorageLive(_4); // scope 1 at $DIR/inline-any-operand.rs:+2:5: +2:13
- _4 = const -1_i32; // scope 1 at $DIR/inline-any-operand.rs:+2:5: +2:13
- StorageLive(_5); // scope 2 at $DIR/inline-any-operand.rs:17:5: 17:6
- _5 = _3; // scope 2 at $DIR/inline-any-operand.rs:17:5: 17:6
- StorageLive(_6); // scope 2 at $DIR/inline-any-operand.rs:17:10: 17:11
- _6 = _4; // scope 2 at $DIR/inline-any-operand.rs:17:10: 17:11
- _0 = Eq(move _5, move _6); // scope 2 at $DIR/inline-any-operand.rs:17:5: 17:11
- StorageDead(_6); // scope 2 at $DIR/inline-any-operand.rs:17:10: 17:11
- StorageDead(_5); // scope 2 at $DIR/inline-any-operand.rs:17:10: 17:11
- StorageDead(_4); // scope 1 at $DIR/inline-any-operand.rs:+2:5: +2:13
- StorageDead(_3); // scope 1 at $DIR/inline-any-operand.rs:+2:5: +2:13
- StorageDead(_2); // scope 1 at $DIR/inline-any-operand.rs:+2:12: +2:13
- StorageDead(_1); // scope 0 at $DIR/inline-any-operand.rs:+3:1: +3:2
- return; // scope 0 at $DIR/inline-any-operand.rs:+3:2: +3:2
+ StorageLive(_2); // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:6
+ _2 = _1; // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:6
+ StorageLive(_3); // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13
+ _3 = const 1_i32; // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13
+ StorageLive(_4); // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13
+ _4 = const -1_i32; // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13
+ StorageLive(_5); // scope 2 at $DIR/inline_any_operand.rs:17:5: 17:6
+ _5 = _3; // scope 2 at $DIR/inline_any_operand.rs:17:5: 17:6
+ StorageLive(_6); // scope 2 at $DIR/inline_any_operand.rs:17:10: 17:11
+ _6 = _4; // scope 2 at $DIR/inline_any_operand.rs:17:10: 17:11
+ _0 = Eq(move _5, move _6); // scope 2 at $DIR/inline_any_operand.rs:17:5: 17:11
+ StorageDead(_6); // scope 2 at $DIR/inline_any_operand.rs:17:10: 17:11
+ StorageDead(_5); // scope 2 at $DIR/inline_any_operand.rs:17:10: 17:11
+ StorageDead(_4); // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13
+ StorageDead(_3); // scope 1 at $DIR/inline_any_operand.rs:+2:5: +2:13
+ StorageDead(_2); // scope 1 at $DIR/inline_any_operand.rs:+2:12: +2:13
+ StorageDead(_1); // scope 0 at $DIR/inline_any_operand.rs:+3:1: +3:2
+ return; // scope 0 at $DIR/inline_any_operand.rs:+3:2: +3:2
}
}
--- /dev/null
+// compile-flags: -Z span_free_formats
+
+// Tests that MIR inliner works for any operand
+
+fn main() {
+ println!("{}", bar());
+}
+
+// EMIT_MIR inline_any_operand.bar.Inline.after.mir
+fn bar() -> bool {
+ let f = foo;
+ f(1, -1)
+}
+
+#[inline(always)]
+fn foo(x: i32, y: i32) -> bool {
+ x == y
+}
--- /dev/null
+// Checks that inliner doesn't introduce cycles when optimizing generators.
+// The outcome of optimization is not verfied, just the absence of the cycle.
+// Regression test for #76181.
+//
+// edition:2018
+
+#![crate_type = "lib"]
+
+pub struct S;
+
+impl S {
+ pub async fn g(&mut self) {
+ self.h();
+ }
+ pub fn h(&mut self) {
+ let _ = self.g();
+ }
+}
// MIR for `foo` after Inline
fn foo(_1: T, _2: i32) -> i32 {
- debug _t => _1; // in scope 0 at $DIR/inline-closure.rs:+0:17: +0:19
- debug q => _2; // in scope 0 at $DIR/inline-closure.rs:+0:24: +0:25
- let mut _0: i32; // return place in scope 0 at $DIR/inline-closure.rs:+0:35: +0:38
- let _3: [closure@foo<T>::{closure#0}]; // in scope 0 at $DIR/inline-closure.rs:+1:9: +1:10
- let mut _4: &[closure@foo<T>::{closure#0}]; // in scope 0 at $DIR/inline-closure.rs:+2:5: +2:6
- let mut _5: (i32, i32); // in scope 0 at $DIR/inline-closure.rs:+2:5: +2:12
- let mut _6: i32; // in scope 0 at $DIR/inline-closure.rs:+2:7: +2:8
- let mut _7: i32; // in scope 0 at $DIR/inline-closure.rs:+2:10: +2:11
- let mut _8: i32; // in scope 0 at $DIR/inline-closure.rs:+2:5: +2:12
- let mut _9: i32; // in scope 0 at $DIR/inline-closure.rs:+2:5: +2:12
+ debug _t => _1; // in scope 0 at $DIR/inline_closure.rs:+0:17: +0:19
+ debug q => _2; // in scope 0 at $DIR/inline_closure.rs:+0:24: +0:25
+ let mut _0: i32; // return place in scope 0 at $DIR/inline_closure.rs:+0:35: +0:38
+ let _3: [closure@foo<T>::{closure#0}]; // in scope 0 at $DIR/inline_closure.rs:+1:9: +1:10
+ let mut _4: &[closure@foo<T>::{closure#0}]; // in scope 0 at $DIR/inline_closure.rs:+2:5: +2:6
+ let mut _5: (i32, i32); // in scope 0 at $DIR/inline_closure.rs:+2:5: +2:12
+ let mut _6: i32; // in scope 0 at $DIR/inline_closure.rs:+2:7: +2:8
+ let mut _7: i32; // in scope 0 at $DIR/inline_closure.rs:+2:10: +2:11
+ let mut _8: i32; // in scope 0 at $DIR/inline_closure.rs:+2:5: +2:12
+ let mut _9: i32; // in scope 0 at $DIR/inline_closure.rs:+2:5: +2:12
scope 1 {
- debug x => _3; // in scope 1 at $DIR/inline-closure.rs:+1:9: +1:10
- scope 2 (inlined foo::<T>::{closure#0}) { // at $DIR/inline-closure.rs:12:5: 12:12
- debug _t => _8; // in scope 2 at $DIR/inline-closure.rs:+1:14: +1:16
- debug _q => _9; // in scope 2 at $DIR/inline-closure.rs:+1:18: +1:20
+ debug x => _3; // in scope 1 at $DIR/inline_closure.rs:+1:9: +1:10
+ scope 2 (inlined foo::<T>::{closure#0}) { // at $DIR/inline_closure.rs:12:5: 12:12
+ debug _t => _8; // in scope 2 at $DIR/inline_closure.rs:+1:14: +1:16
+ debug _q => _9; // in scope 2 at $DIR/inline_closure.rs:+1:18: +1:20
}
}
bb0: {
- StorageLive(_3); // scope 0 at $DIR/inline-closure.rs:+1:9: +1:10
- Deinit(_3); // scope 0 at $DIR/inline-closure.rs:+1:13: +1:24
- StorageLive(_4); // scope 1 at $DIR/inline-closure.rs:+2:5: +2:6
- _4 = &_3; // scope 1 at $DIR/inline-closure.rs:+2:5: +2:6
- StorageLive(_5); // scope 1 at $DIR/inline-closure.rs:+2:5: +2:12
- StorageLive(_6); // scope 1 at $DIR/inline-closure.rs:+2:7: +2:8
- _6 = _2; // scope 1 at $DIR/inline-closure.rs:+2:7: +2:8
- StorageLive(_7); // scope 1 at $DIR/inline-closure.rs:+2:10: +2:11
- _7 = _2; // scope 1 at $DIR/inline-closure.rs:+2:10: +2:11
- Deinit(_5); // scope 1 at $DIR/inline-closure.rs:+2:5: +2:12
- (_5.0: i32) = move _6; // scope 1 at $DIR/inline-closure.rs:+2:5: +2:12
- (_5.1: i32) = move _7; // scope 1 at $DIR/inline-closure.rs:+2:5: +2:12
- StorageLive(_8); // scope 1 at $DIR/inline-closure.rs:+2:5: +2:12
- _8 = move (_5.0: i32); // scope 1 at $DIR/inline-closure.rs:+2:5: +2:12
- StorageLive(_9); // scope 1 at $DIR/inline-closure.rs:+2:5: +2:12
- _9 = move (_5.1: i32); // scope 1 at $DIR/inline-closure.rs:+2:5: +2:12
- _0 = _8; // scope 2 at $DIR/inline-closure.rs:+1:22: +1:24
- StorageDead(_9); // scope 1 at $DIR/inline-closure.rs:+2:5: +2:12
- StorageDead(_8); // scope 1 at $DIR/inline-closure.rs:+2:5: +2:12
- StorageDead(_7); // scope 1 at $DIR/inline-closure.rs:+2:11: +2:12
- StorageDead(_6); // scope 1 at $DIR/inline-closure.rs:+2:11: +2:12
- StorageDead(_5); // scope 1 at $DIR/inline-closure.rs:+2:11: +2:12
- StorageDead(_4); // scope 1 at $DIR/inline-closure.rs:+2:11: +2:12
- StorageDead(_3); // scope 0 at $DIR/inline-closure.rs:+3:1: +3:2
- return; // scope 0 at $DIR/inline-closure.rs:+3:2: +3:2
+ StorageLive(_3); // scope 0 at $DIR/inline_closure.rs:+1:9: +1:10
+ Deinit(_3); // scope 0 at $DIR/inline_closure.rs:+1:13: +1:24
+ StorageLive(_4); // scope 1 at $DIR/inline_closure.rs:+2:5: +2:6
+ _4 = &_3; // scope 1 at $DIR/inline_closure.rs:+2:5: +2:6
+ StorageLive(_5); // scope 1 at $DIR/inline_closure.rs:+2:5: +2:12
+ StorageLive(_6); // scope 1 at $DIR/inline_closure.rs:+2:7: +2:8
+ _6 = _2; // scope 1 at $DIR/inline_closure.rs:+2:7: +2:8
+ StorageLive(_7); // scope 1 at $DIR/inline_closure.rs:+2:10: +2:11
+ _7 = _2; // scope 1 at $DIR/inline_closure.rs:+2:10: +2:11
+ Deinit(_5); // scope 1 at $DIR/inline_closure.rs:+2:5: +2:12
+ (_5.0: i32) = move _6; // scope 1 at $DIR/inline_closure.rs:+2:5: +2:12
+ (_5.1: i32) = move _7; // scope 1 at $DIR/inline_closure.rs:+2:5: +2:12
+ StorageLive(_8); // scope 1 at $DIR/inline_closure.rs:+2:5: +2:12
+ _8 = move (_5.0: i32); // scope 1 at $DIR/inline_closure.rs:+2:5: +2:12
+ StorageLive(_9); // scope 1 at $DIR/inline_closure.rs:+2:5: +2:12
+ _9 = move (_5.1: i32); // scope 1 at $DIR/inline_closure.rs:+2:5: +2:12
+ _0 = _8; // scope 2 at $DIR/inline_closure.rs:+1:22: +1:24
+ StorageDead(_9); // scope 1 at $DIR/inline_closure.rs:+2:5: +2:12
+ StorageDead(_8); // scope 1 at $DIR/inline_closure.rs:+2:5: +2:12
+ StorageDead(_7); // scope 1 at $DIR/inline_closure.rs:+2:11: +2:12
+ StorageDead(_6); // scope 1 at $DIR/inline_closure.rs:+2:11: +2:12
+ StorageDead(_5); // scope 1 at $DIR/inline_closure.rs:+2:11: +2:12
+ StorageDead(_4); // scope 1 at $DIR/inline_closure.rs:+2:11: +2:12
+ StorageDead(_3); // scope 0 at $DIR/inline_closure.rs:+3:1: +3:2
+ return; // scope 0 at $DIR/inline_closure.rs:+3:2: +3:2
}
}
--- /dev/null
+// compile-flags: -Z span_free_formats
+
+// Tests that MIR inliner can handle closure arguments. (#45894)
+
+fn main() {
+ println!("{}", foo(0, 14));
+}
+
+// EMIT_MIR inline_closure.foo.Inline.after.mir
+fn foo<T: Copy>(_t: T, q: i32) -> i32 {
+ let x = |_t, _q| _t;
+ x(q, q)
+}
// MIR for `foo` after Inline
fn foo(_1: T, _2: &i32) -> i32 {
- debug _t => _1; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:+0:17: +0:19
- debug q => _2; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:+0:24: +0:25
- let mut _0: i32; // return place in scope 0 at $DIR/inline-closure-borrows-arg.rs:+0:36: +0:39
- let _3: [closure@foo<T>::{closure#0}]; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:+1:9: +1:10
- let mut _4: &[closure@foo<T>::{closure#0}]; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:6
- let mut _5: (&i32, &i32); // in scope 0 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:12
- let mut _6: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:+5:7: +5:8
- let mut _7: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:+5:10: +5:11
- let mut _8: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:12
- let mut _9: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:12
+ debug _t => _1; // in scope 0 at $DIR/inline_closure_borrows_arg.rs:+0:17: +0:19
+ debug q => _2; // in scope 0 at $DIR/inline_closure_borrows_arg.rs:+0:24: +0:25
+ let mut _0: i32; // return place in scope 0 at $DIR/inline_closure_borrows_arg.rs:+0:36: +0:39
+ let _3: [closure@foo<T>::{closure#0}]; // in scope 0 at $DIR/inline_closure_borrows_arg.rs:+1:9: +1:10
+ let mut _4: &[closure@foo<T>::{closure#0}]; // in scope 0 at $DIR/inline_closure_borrows_arg.rs:+5:5: +5:6
+ let mut _5: (&i32, &i32); // in scope 0 at $DIR/inline_closure_borrows_arg.rs:+5:5: +5:12
+ let mut _6: &i32; // in scope 0 at $DIR/inline_closure_borrows_arg.rs:+5:7: +5:8
+ let mut _7: &i32; // in scope 0 at $DIR/inline_closure_borrows_arg.rs:+5:10: +5:11
+ let mut _8: &i32; // in scope 0 at $DIR/inline_closure_borrows_arg.rs:+5:5: +5:12
+ let mut _9: &i32; // in scope 0 at $DIR/inline_closure_borrows_arg.rs:+5:5: +5:12
scope 1 {
- debug x => _3; // in scope 1 at $DIR/inline-closure-borrows-arg.rs:+1:9: +1:10
- scope 2 (inlined foo::<T>::{closure#0}) { // at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
- debug r => _8; // in scope 2 at $DIR/inline-closure-borrows-arg.rs:+1:14: +1:15
- debug _s => _9; // in scope 2 at $DIR/inline-closure-borrows-arg.rs:+1:23: +1:25
- let _10: &i32; // in scope 2 at $DIR/inline-closure-borrows-arg.rs:+2:13: +2:21
+ debug x => _3; // in scope 1 at $DIR/inline_closure_borrows_arg.rs:+1:9: +1:10
+ scope 2 (inlined foo::<T>::{closure#0}) { // at $DIR/inline_closure_borrows_arg.rs:16:5: 16:12
+ debug r => _8; // in scope 2 at $DIR/inline_closure_borrows_arg.rs:+1:14: +1:15
+ debug _s => _9; // in scope 2 at $DIR/inline_closure_borrows_arg.rs:+1:23: +1:25
+ let _10: &i32; // in scope 2 at $DIR/inline_closure_borrows_arg.rs:+2:13: +2:21
scope 3 {
- debug variable => _10; // in scope 3 at $DIR/inline-closure-borrows-arg.rs:+2:13: +2:21
+ debug variable => _10; // in scope 3 at $DIR/inline_closure_borrows_arg.rs:+2:13: +2:21
}
}
}
bb0: {
- StorageLive(_3); // scope 0 at $DIR/inline-closure-borrows-arg.rs:+1:9: +1:10
- Deinit(_3); // scope 0 at $DIR/inline-closure-borrows-arg.rs:+1:13: +4:6
- StorageLive(_4); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:6
- _4 = &_3; // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:6
- StorageLive(_5); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:12
- StorageLive(_6); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:7: +5:8
- _6 = &(*_2); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:7: +5:8
- StorageLive(_7); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:10: +5:11
- _7 = &(*_2); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:10: +5:11
- Deinit(_5); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:12
- (_5.0: &i32) = move _6; // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:12
- (_5.1: &i32) = move _7; // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:12
- StorageLive(_8); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:12
- _8 = move (_5.0: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:12
- StorageLive(_9); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:12
- _9 = move (_5.1: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:12
- StorageLive(_10); // scope 2 at $DIR/inline-closure-borrows-arg.rs:+2:13: +2:21
- _10 = _8; // scope 2 at $DIR/inline-closure-borrows-arg.rs:+2:24: +2:27
- _0 = (*_10); // scope 3 at $DIR/inline-closure-borrows-arg.rs:+3:9: +3:18
- StorageDead(_10); // scope 2 at $DIR/inline-closure-borrows-arg.rs:+4:5: +4:6
- StorageDead(_9); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:12
- StorageDead(_8); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:5: +5:12
- StorageDead(_7); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:11: +5:12
- StorageDead(_6); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:11: +5:12
- StorageDead(_5); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:11: +5:12
- StorageDead(_4); // scope 1 at $DIR/inline-closure-borrows-arg.rs:+5:11: +5:12
- StorageDead(_3); // scope 0 at $DIR/inline-closure-borrows-arg.rs:+6:1: +6:2
- return; // scope 0 at $DIR/inline-closure-borrows-arg.rs:+6:2: +6:2
+ StorageLive(_3); // scope 0 at $DIR/inline_closure_borrows_arg.rs:+1:9: +1:10
+ Deinit(_3); // scope 0 at $DIR/inline_closure_borrows_arg.rs:+1:13: +4:6
+ StorageLive(_4); // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:5: +5:6
+ _4 = &_3; // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:5: +5:6
+ StorageLive(_5); // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:5: +5:12
+ StorageLive(_6); // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:7: +5:8
+ _6 = &(*_2); // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:7: +5:8
+ StorageLive(_7); // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:10: +5:11
+ _7 = &(*_2); // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:10: +5:11
+ Deinit(_5); // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:5: +5:12
+ (_5.0: &i32) = move _6; // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:5: +5:12
+ (_5.1: &i32) = move _7; // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:5: +5:12
+ StorageLive(_8); // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:5: +5:12
+ _8 = move (_5.0: &i32); // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:5: +5:12
+ StorageLive(_9); // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:5: +5:12
+ _9 = move (_5.1: &i32); // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:5: +5:12
+ StorageLive(_10); // scope 2 at $DIR/inline_closure_borrows_arg.rs:+2:13: +2:21
+ _10 = _8; // scope 2 at $DIR/inline_closure_borrows_arg.rs:+2:24: +2:27
+ _0 = (*_10); // scope 3 at $DIR/inline_closure_borrows_arg.rs:+3:9: +3:18
+ StorageDead(_10); // scope 2 at $DIR/inline_closure_borrows_arg.rs:+4:5: +4:6
+ StorageDead(_9); // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:5: +5:12
+ StorageDead(_8); // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:5: +5:12
+ StorageDead(_7); // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:11: +5:12
+ StorageDead(_6); // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:11: +5:12
+ StorageDead(_5); // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:11: +5:12
+ StorageDead(_4); // scope 1 at $DIR/inline_closure_borrows_arg.rs:+5:11: +5:12
+ StorageDead(_3); // scope 0 at $DIR/inline_closure_borrows_arg.rs:+6:1: +6:2
+ return; // scope 0 at $DIR/inline_closure_borrows_arg.rs:+6:2: +6:2
}
}
--- /dev/null
+// compile-flags: -Z span_free_formats -Zunsound-mir-opts
+
+// Tests that MIR inliner can handle closure arguments,
+// even when (#45894)
+
+fn main() {
+ println!("{}", foo(0, &14));
+}
+
+// EMIT_MIR inline_closure_borrows_arg.foo.Inline.after.mir
+fn foo<T: Copy>(_t: T, q: &i32) -> i32 {
+ let x = |r: &i32, _s: &i32| {
+ let variable = &*r;
+ *variable
+ };
+ x(q, q)
+}
// MIR for `foo` after Inline
fn foo(_1: T, _2: i32) -> (i32, T) {
- debug t => _1; // in scope 0 at $DIR/inline-closure-captures.rs:+0:17: +0:18
- debug q => _2; // in scope 0 at $DIR/inline-closure-captures.rs:+0:23: +0:24
- let mut _0: (i32, T); // return place in scope 0 at $DIR/inline-closure-captures.rs:+0:34: +0:42
- let _3: [closure@foo<T>::{closure#0}]; // in scope 0 at $DIR/inline-closure-captures.rs:+1:9: +1:10
- let mut _4: &i32; // in scope 0 at $DIR/inline-closure-captures.rs:+1:13: +1:24
- let mut _5: &T; // in scope 0 at $DIR/inline-closure-captures.rs:+1:13: +1:24
- let mut _6: &[closure@foo<T>::{closure#0}]; // in scope 0 at $DIR/inline-closure-captures.rs:+2:5: +2:6
- let mut _7: (i32,); // in scope 0 at $DIR/inline-closure-captures.rs:+2:5: +2:9
- let mut _8: i32; // in scope 0 at $DIR/inline-closure-captures.rs:+2:7: +2:8
- let mut _9: i32; // in scope 0 at $DIR/inline-closure-captures.rs:+2:5: +2:9
+ debug t => _1; // in scope 0 at $DIR/inline_closure_captures.rs:+0:17: +0:18
+ debug q => _2; // in scope 0 at $DIR/inline_closure_captures.rs:+0:23: +0:24
+ let mut _0: (i32, T); // return place in scope 0 at $DIR/inline_closure_captures.rs:+0:34: +0:42
+ let _3: [closure@foo<T>::{closure#0}]; // in scope 0 at $DIR/inline_closure_captures.rs:+1:9: +1:10
+ let mut _4: &i32; // in scope 0 at $DIR/inline_closure_captures.rs:+1:13: +1:24
+ let mut _5: &T; // in scope 0 at $DIR/inline_closure_captures.rs:+1:13: +1:24
+ let mut _6: &[closure@foo<T>::{closure#0}]; // in scope 0 at $DIR/inline_closure_captures.rs:+2:5: +2:6
+ let mut _7: (i32,); // in scope 0 at $DIR/inline_closure_captures.rs:+2:5: +2:9
+ let mut _8: i32; // in scope 0 at $DIR/inline_closure_captures.rs:+2:7: +2:8
+ let mut _9: i32; // in scope 0 at $DIR/inline_closure_captures.rs:+2:5: +2:9
scope 1 {
- debug x => _3; // in scope 1 at $DIR/inline-closure-captures.rs:+1:9: +1:10
- scope 2 (inlined foo::<T>::{closure#0}) { // at $DIR/inline-closure-captures.rs:12:5: 12:9
- debug _q => _9; // in scope 2 at $DIR/inline-closure-captures.rs:+1:14: +1:16
- debug q => (*((*_6).0: &i32)); // in scope 2 at $DIR/inline-closure-captures.rs:+0:23: +0:24
- debug t => (*((*_6).1: &T)); // in scope 2 at $DIR/inline-closure-captures.rs:+0:17: +0:18
- let mut _10: i32; // in scope 2 at $DIR/inline-closure-captures.rs:+1:19: +1:20
- let mut _11: T; // in scope 2 at $DIR/inline-closure-captures.rs:+1:22: +1:23
- let mut _12: &i32; // in scope 2 at $DIR/inline-closure-captures.rs:+1:13: +1:24
- let mut _13: &T; // in scope 2 at $DIR/inline-closure-captures.rs:+1:13: +1:24
+ debug x => _3; // in scope 1 at $DIR/inline_closure_captures.rs:+1:9: +1:10
+ scope 2 (inlined foo::<T>::{closure#0}) { // at $DIR/inline_closure_captures.rs:12:5: 12:9
+ debug _q => _9; // in scope 2 at $DIR/inline_closure_captures.rs:+1:14: +1:16
+ debug q => (*((*_6).0: &i32)); // in scope 2 at $DIR/inline_closure_captures.rs:+0:23: +0:24
+ debug t => (*((*_6).1: &T)); // in scope 2 at $DIR/inline_closure_captures.rs:+0:17: +0:18
+ let mut _10: i32; // in scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20
+ let mut _11: T; // in scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23
+ let mut _12: &i32; // in scope 2 at $DIR/inline_closure_captures.rs:+1:13: +1:24
+ let mut _13: &T; // in scope 2 at $DIR/inline_closure_captures.rs:+1:13: +1:24
}
}
bb0: {
- StorageLive(_3); // scope 0 at $DIR/inline-closure-captures.rs:+1:9: +1:10
- StorageLive(_4); // scope 0 at $DIR/inline-closure-captures.rs:+1:13: +1:24
- _4 = &_2; // scope 0 at $DIR/inline-closure-captures.rs:+1:13: +1:24
- StorageLive(_5); // scope 0 at $DIR/inline-closure-captures.rs:+1:13: +1:24
- _5 = &_1; // scope 0 at $DIR/inline-closure-captures.rs:+1:13: +1:24
- Deinit(_3); // scope 0 at $DIR/inline-closure-captures.rs:+1:13: +1:24
- (_3.0: &i32) = move _4; // scope 0 at $DIR/inline-closure-captures.rs:+1:13: +1:24
- (_3.1: &T) = move _5; // scope 0 at $DIR/inline-closure-captures.rs:+1:13: +1:24
- StorageDead(_5); // scope 0 at $DIR/inline-closure-captures.rs:+1:16: +1:17
- StorageDead(_4); // scope 0 at $DIR/inline-closure-captures.rs:+1:16: +1:17
- StorageLive(_6); // scope 1 at $DIR/inline-closure-captures.rs:+2:5: +2:6
- _6 = &_3; // scope 1 at $DIR/inline-closure-captures.rs:+2:5: +2:6
- StorageLive(_7); // scope 1 at $DIR/inline-closure-captures.rs:+2:5: +2:9
- StorageLive(_8); // scope 1 at $DIR/inline-closure-captures.rs:+2:7: +2:8
- _8 = _2; // scope 1 at $DIR/inline-closure-captures.rs:+2:7: +2:8
- Deinit(_7); // scope 1 at $DIR/inline-closure-captures.rs:+2:5: +2:9
- (_7.0: i32) = move _8; // scope 1 at $DIR/inline-closure-captures.rs:+2:5: +2:9
- StorageLive(_9); // scope 1 at $DIR/inline-closure-captures.rs:+2:5: +2:9
- _9 = move (_7.0: i32); // scope 1 at $DIR/inline-closure-captures.rs:+2:5: +2:9
- StorageLive(_10); // scope 2 at $DIR/inline-closure-captures.rs:+1:19: +1:20
- _12 = deref_copy ((*_6).0: &i32); // scope 2 at $DIR/inline-closure-captures.rs:+1:19: +1:20
- _10 = (*_12); // scope 2 at $DIR/inline-closure-captures.rs:+1:19: +1:20
- StorageLive(_11); // scope 2 at $DIR/inline-closure-captures.rs:+1:22: +1:23
- _13 = deref_copy ((*_6).1: &T); // scope 2 at $DIR/inline-closure-captures.rs:+1:22: +1:23
- _11 = (*_13); // scope 2 at $DIR/inline-closure-captures.rs:+1:22: +1:23
- Deinit(_0); // scope 2 at $DIR/inline-closure-captures.rs:+1:18: +1:24
- (_0.0: i32) = move _10; // scope 2 at $DIR/inline-closure-captures.rs:+1:18: +1:24
- (_0.1: T) = move _11; // scope 2 at $DIR/inline-closure-captures.rs:+1:18: +1:24
- StorageDead(_11); // scope 2 at $DIR/inline-closure-captures.rs:+1:23: +1:24
- StorageDead(_10); // scope 2 at $DIR/inline-closure-captures.rs:+1:23: +1:24
- StorageDead(_9); // scope 1 at $DIR/inline-closure-captures.rs:+2:5: +2:9
- StorageDead(_8); // scope 1 at $DIR/inline-closure-captures.rs:+2:8: +2:9
- StorageDead(_7); // scope 1 at $DIR/inline-closure-captures.rs:+2:8: +2:9
- StorageDead(_6); // scope 1 at $DIR/inline-closure-captures.rs:+2:8: +2:9
- StorageDead(_3); // scope 0 at $DIR/inline-closure-captures.rs:+3:1: +3:2
- return; // scope 0 at $DIR/inline-closure-captures.rs:+3:2: +3:2
+ StorageLive(_3); // scope 0 at $DIR/inline_closure_captures.rs:+1:9: +1:10
+ StorageLive(_4); // scope 0 at $DIR/inline_closure_captures.rs:+1:13: +1:24
+ _4 = &_2; // scope 0 at $DIR/inline_closure_captures.rs:+1:13: +1:24
+ StorageLive(_5); // scope 0 at $DIR/inline_closure_captures.rs:+1:13: +1:24
+ _5 = &_1; // scope 0 at $DIR/inline_closure_captures.rs:+1:13: +1:24
+ Deinit(_3); // scope 0 at $DIR/inline_closure_captures.rs:+1:13: +1:24
+ (_3.0: &i32) = move _4; // scope 0 at $DIR/inline_closure_captures.rs:+1:13: +1:24
+ (_3.1: &T) = move _5; // scope 0 at $DIR/inline_closure_captures.rs:+1:13: +1:24
+ StorageDead(_5); // scope 0 at $DIR/inline_closure_captures.rs:+1:16: +1:17
+ StorageDead(_4); // scope 0 at $DIR/inline_closure_captures.rs:+1:16: +1:17
+ StorageLive(_6); // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:6
+ _6 = &_3; // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:6
+ StorageLive(_7); // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:9
+ StorageLive(_8); // scope 1 at $DIR/inline_closure_captures.rs:+2:7: +2:8
+ _8 = _2; // scope 1 at $DIR/inline_closure_captures.rs:+2:7: +2:8
+ Deinit(_7); // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:9
+ (_7.0: i32) = move _8; // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:9
+ StorageLive(_9); // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:9
+ _9 = move (_7.0: i32); // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:9
+ StorageLive(_10); // scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20
+ _12 = deref_copy ((*_6).0: &i32); // scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20
+ _10 = (*_12); // scope 2 at $DIR/inline_closure_captures.rs:+1:19: +1:20
+ StorageLive(_11); // scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23
+ _13 = deref_copy ((*_6).1: &T); // scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23
+ _11 = (*_13); // scope 2 at $DIR/inline_closure_captures.rs:+1:22: +1:23
+ Deinit(_0); // scope 2 at $DIR/inline_closure_captures.rs:+1:18: +1:24
+ (_0.0: i32) = move _10; // scope 2 at $DIR/inline_closure_captures.rs:+1:18: +1:24
+ (_0.1: T) = move _11; // scope 2 at $DIR/inline_closure_captures.rs:+1:18: +1:24
+ StorageDead(_11); // scope 2 at $DIR/inline_closure_captures.rs:+1:23: +1:24
+ StorageDead(_10); // scope 2 at $DIR/inline_closure_captures.rs:+1:23: +1:24
+ StorageDead(_9); // scope 1 at $DIR/inline_closure_captures.rs:+2:5: +2:9
+ StorageDead(_8); // scope 1 at $DIR/inline_closure_captures.rs:+2:8: +2:9
+ StorageDead(_7); // scope 1 at $DIR/inline_closure_captures.rs:+2:8: +2:9
+ StorageDead(_6); // scope 1 at $DIR/inline_closure_captures.rs:+2:8: +2:9
+ StorageDead(_3); // scope 0 at $DIR/inline_closure_captures.rs:+3:1: +3:2
+ return; // scope 0 at $DIR/inline_closure_captures.rs:+3:2: +3:2
}
}
--- /dev/null
+// compile-flags: -Z span_free_formats
+
+// Tests that MIR inliner can handle closure captures.
+
+fn main() {
+ println!("{:?}", foo(0, 14));
+}
+
+// EMIT_MIR inline_closure_captures.foo.Inline.after.mir
+fn foo<T: Copy>(t: T, q: i32) -> (i32, T) {
+ let x = |_q| (q, t);
+ x(q)
+}
+ // MIR for `inlined_no_sanitize` after Inline
fn inlined_no_sanitize() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:+0:37: +0:37
- let _1: (); // in scope 0 at $DIR/inline-compatibility.rs:+1:5: +1:18
-+ scope 1 (inlined no_sanitize) { // at $DIR/inline-compatibility.rs:24:5: 24:18
+ let mut _0: (); // return place in scope 0 at $DIR/inline_compatibility.rs:+0:37: +0:37
+ let _1: (); // in scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:18
++ scope 1 (inlined no_sanitize) { // at $DIR/inline_compatibility.rs:24:5: 24:18
+ }
bb0: {
- StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:+1:5: +1:18
-- _1 = no_sanitize() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:+1:5: +1:18
+ StorageLive(_1); // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:18
+- _1 = no_sanitize() -> bb1; // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:18
- // mir::Constant
-- // + span: $DIR/inline-compatibility.rs:24:5: 24:16
+- // + span: $DIR/inline_compatibility.rs:24:5: 24:16
- // + literal: Const { ty: unsafe fn() {no_sanitize}, val: Value(<ZST>) }
- }
-
- bb1: {
- StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:+1:18: +1:19
- _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:+0:37: +2:2
- return; // scope 0 at $DIR/inline-compatibility.rs:+2:2: +2:2
+ StorageDead(_1); // scope 0 at $DIR/inline_compatibility.rs:+1:18: +1:19
+ _0 = const (); // scope 0 at $DIR/inline_compatibility.rs:+0:37: +2:2
+ return; // scope 0 at $DIR/inline_compatibility.rs:+2:2: +2:2
}
}
+ // MIR for `inlined_target_feature` after Inline
fn inlined_target_feature() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:+0:40: +0:40
- let _1: (); // in scope 0 at $DIR/inline-compatibility.rs:+1:5: +1:21
-+ scope 1 (inlined target_feature) { // at $DIR/inline-compatibility.rs:13:5: 13:21
+ let mut _0: (); // return place in scope 0 at $DIR/inline_compatibility.rs:+0:40: +0:40
+ let _1: (); // in scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:21
++ scope 1 (inlined target_feature) { // at $DIR/inline_compatibility.rs:13:5: 13:21
+ }
bb0: {
- StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:+1:5: +1:21
-- _1 = target_feature() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:+1:5: +1:21
+ StorageLive(_1); // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:21
+- _1 = target_feature() -> bb1; // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:21
- // mir::Constant
-- // + span: $DIR/inline-compatibility.rs:13:5: 13:19
+- // + span: $DIR/inline_compatibility.rs:13:5: 13:19
- // + literal: Const { ty: unsafe fn() {target_feature}, val: Value(<ZST>) }
- }
-
- bb1: {
- StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:+1:21: +1:22
- _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:+0:40: +2:2
- return; // scope 0 at $DIR/inline-compatibility.rs:+2:2: +2:2
+ StorageDead(_1); // scope 0 at $DIR/inline_compatibility.rs:+1:21: +1:22
+ _0 = const (); // scope 0 at $DIR/inline_compatibility.rs:+0:40: +2:2
+ return; // scope 0 at $DIR/inline_compatibility.rs:+2:2: +2:2
}
}
+ // MIR for `not_inlined_c_variadic` after Inline
fn not_inlined_c_variadic() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:+0:40: +0:40
- let _1: u32; // in scope 0 at $DIR/inline-compatibility.rs:+1:9: +1:10
+ let mut _0: (); // return place in scope 0 at $DIR/inline_compatibility.rs:+0:40: +0:40
+ let _1: u32; // in scope 0 at $DIR/inline_compatibility.rs:+1:9: +1:10
scope 1 {
- debug s => _1; // in scope 1 at $DIR/inline-compatibility.rs:+1:9: +1:10
+ debug s => _1; // in scope 1 at $DIR/inline_compatibility.rs:+1:9: +1:10
}
bb0: {
- StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:+1:9: +1:10
- _1 = sum(const 4_u32, const 4_u32, const 30_u32, const 200_u32, const 1000_u32) -> bb1; // scope 0 at $DIR/inline-compatibility.rs:+1:13: +1:52
+ StorageLive(_1); // scope 0 at $DIR/inline_compatibility.rs:+1:9: +1:10
+ _1 = sum(const 4_u32, const 4_u32, const 30_u32, const 200_u32, const 1000_u32) -> bb1; // scope 0 at $DIR/inline_compatibility.rs:+1:13: +1:52
// mir::Constant
- // + span: $DIR/inline-compatibility.rs:42:13: 42:16
+ // + span: $DIR/inline_compatibility.rs:42:13: 42:16
// + literal: Const { ty: unsafe extern "C" fn(u32, ...) -> u32 {sum}, val: Value(<ZST>) }
}
bb1: {
- _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:+0:40: +2:2
- StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:+2:1: +2:2
- return; // scope 0 at $DIR/inline-compatibility.rs:+2:2: +2:2
+ _0 = const (); // scope 0 at $DIR/inline_compatibility.rs:+0:40: +2:2
+ StorageDead(_1); // scope 0 at $DIR/inline_compatibility.rs:+2:1: +2:2
+ return; // scope 0 at $DIR/inline_compatibility.rs:+2:2: +2:2
}
}
+ // MIR for `not_inlined_no_sanitize` after Inline
fn not_inlined_no_sanitize() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:+0:41: +0:41
- let _1: (); // in scope 0 at $DIR/inline-compatibility.rs:+1:5: +1:18
+ let mut _0: (); // return place in scope 0 at $DIR/inline_compatibility.rs:+0:41: +0:41
+ let _1: (); // in scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:18
bb0: {
- StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:+1:5: +1:18
- _1 = no_sanitize() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:+1:5: +1:18
+ StorageLive(_1); // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:18
+ _1 = no_sanitize() -> bb1; // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:18
// mir::Constant
- // + span: $DIR/inline-compatibility.rs:29:5: 29:16
+ // + span: $DIR/inline_compatibility.rs:29:5: 29:16
// + literal: Const { ty: unsafe fn() {no_sanitize}, val: Value(<ZST>) }
}
bb1: {
- StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:+1:18: +1:19
- _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:+0:41: +2:2
- return; // scope 0 at $DIR/inline-compatibility.rs:+2:2: +2:2
+ StorageDead(_1); // scope 0 at $DIR/inline_compatibility.rs:+1:18: +1:19
+ _0 = const (); // scope 0 at $DIR/inline_compatibility.rs:+0:41: +2:2
+ return; // scope 0 at $DIR/inline_compatibility.rs:+2:2: +2:2
}
}
+ // MIR for `not_inlined_target_feature` after Inline
fn not_inlined_target_feature() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:+0:44: +0:44
- let _1: (); // in scope 0 at $DIR/inline-compatibility.rs:+1:5: +1:21
+ let mut _0: (); // return place in scope 0 at $DIR/inline_compatibility.rs:+0:44: +0:44
+ let _1: (); // in scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:21
bb0: {
- StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:+1:5: +1:21
- _1 = target_feature() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:+1:5: +1:21
+ StorageLive(_1); // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:21
+ _1 = target_feature() -> bb1; // scope 0 at $DIR/inline_compatibility.rs:+1:5: +1:21
// mir::Constant
- // + span: $DIR/inline-compatibility.rs:18:5: 18:19
+ // + span: $DIR/inline_compatibility.rs:18:5: 18:19
// + literal: Const { ty: unsafe fn() {target_feature}, val: Value(<ZST>) }
}
bb1: {
- StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:+1:21: +1:22
- _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:+0:44: +2:2
- return; // scope 0 at $DIR/inline-compatibility.rs:+2:2: +2:2
+ StorageDead(_1); // scope 0 at $DIR/inline_compatibility.rs:+1:21: +1:22
+ _0 = const (); // scope 0 at $DIR/inline_compatibility.rs:+0:44: +2:2
+ return; // scope 0 at $DIR/inline_compatibility.rs:+2:2: +2:2
}
}
--- /dev/null
+// Checks that only functions with compatible attributes are inlined.
+//
+// only-x86_64
+
+#![crate_type = "lib"]
+#![feature(no_sanitize)]
+#![feature(target_feature_11)]
+#![feature(c_variadic)]
+
+// EMIT_MIR inline_compatibility.inlined_target_feature.Inline.diff
+#[target_feature(enable = "sse2")]
+pub unsafe fn inlined_target_feature() {
+ target_feature();
+}
+
+// EMIT_MIR inline_compatibility.not_inlined_target_feature.Inline.diff
+pub unsafe fn not_inlined_target_feature() {
+ target_feature();
+}
+
+// EMIT_MIR inline_compatibility.inlined_no_sanitize.Inline.diff
+#[no_sanitize(address)]
+pub unsafe fn inlined_no_sanitize() {
+ no_sanitize();
+}
+
+// EMIT_MIR inline_compatibility.not_inlined_no_sanitize.Inline.diff
+pub unsafe fn not_inlined_no_sanitize() {
+ no_sanitize();
+}
+
+#[inline]
+#[target_feature(enable = "sse2")]
+pub unsafe fn target_feature() {}
+
+#[inline]
+#[no_sanitize(address)]
+pub unsafe fn no_sanitize() {}
+
+// EMIT_MIR inline_compatibility.not_inlined_c_variadic.Inline.diff
+pub unsafe fn not_inlined_c_variadic() {
+ let s = sum(4u32, 4u32, 30u32, 200u32, 1000u32);
+}
+
+#[no_mangle]
+#[inline(always)]
+unsafe extern "C" fn sum(n: u32, mut vs: ...) -> u32 {
+ let mut s = 0;
+ let mut i = 0;
+ while i != n {
+ s += vs.arg::<u32>();
+ i += 1;
+ }
+ s
+}
+ // MIR for `one` after Inline
fn one() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/inline-cycle.rs:+0:10: +0:10
- let _1: (); // in scope 0 at $DIR/inline-cycle.rs:+1:5: +1:24
-+ scope 1 (inlined <C as Call>::call) { // at $DIR/inline-cycle.rs:14:5: 14:24
-+ scope 2 (inlined <A<C> as Call>::call) { // at $DIR/inline-cycle.rs:43:9: 43:23
-+ scope 3 (inlined <B<C> as Call>::call) { // at $DIR/inline-cycle.rs:28:9: 28:31
+ let mut _0: (); // return place in scope 0 at $DIR/inline_cycle.rs:+0:10: +0:10
+ let _1: (); // in scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
++ scope 1 (inlined <C as Call>::call) { // at $DIR/inline_cycle.rs:14:5: 14:24
++ scope 2 (inlined <A<C> as Call>::call) { // at $DIR/inline_cycle.rs:43:9: 43:23
++ scope 3 (inlined <B<C> as Call>::call) { // at $DIR/inline_cycle.rs:28:9: 28:31
+ }
+ }
+ }
bb0: {
- StorageLive(_1); // scope 0 at $DIR/inline-cycle.rs:+1:5: +1:24
-- _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline-cycle.rs:+1:5: +1:24
-+ _1 = <C as Call>::call() -> bb1; // scope 3 at $DIR/inline-cycle.rs:36:9: 36:28
+ StorageLive(_1); // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
+- _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:24
++ _1 = <C as Call>::call() -> bb1; // scope 3 at $DIR/inline_cycle.rs:36:9: 36:28
// mir::Constant
-- // + span: $DIR/inline-cycle.rs:14:5: 14:22
-+ // + span: $DIR/inline-cycle.rs:36:9: 36:26
+- // + span: $DIR/inline_cycle.rs:14:5: 14:22
++ // + span: $DIR/inline_cycle.rs:36:9: 36:26
// + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
}
bb1: {
- StorageDead(_1); // scope 0 at $DIR/inline-cycle.rs:+1:24: +1:25
- _0 = const (); // scope 0 at $DIR/inline-cycle.rs:+0:10: +2:2
- return; // scope 0 at $DIR/inline-cycle.rs:+2:2: +2:2
+ StorageDead(_1); // scope 0 at $DIR/inline_cycle.rs:+1:24: +1:25
+ _0 = const (); // scope 0 at $DIR/inline_cycle.rs:+0:10: +2:2
+ return; // scope 0 at $DIR/inline_cycle.rs:+2:2: +2:2
}
}
--- /dev/null
+// Check that inliner handles various forms of recursion and doesn't fall into
+// an infinite inlining cycle. The particular outcome of inlining is not
+// crucial otherwise.
+//
+// Regression test for issue #78573.
+
+fn main() {
+ one();
+ two();
+}
+
+// EMIT_MIR inline_cycle.one.Inline.diff
+fn one() {
+ <C as Call>::call();
+}
+
+pub trait Call {
+ fn call();
+}
+
+pub struct A<T>(T);
+pub struct B<T>(T);
+pub struct C;
+
+impl<T: Call> Call for A<T> {
+ #[inline]
+ fn call() {
+ <B<T> as Call>::call()
+ }
+}
+
+
+impl<T: Call> Call for B<T> {
+ #[inline]
+ fn call() {
+ <T as Call>::call()
+ }
+}
+
+impl Call for C {
+ #[inline]
+ fn call() {
+ A::<C>::call()
+ }
+}
+
+// EMIT_MIR inline_cycle.two.Inline.diff
+fn two() {
+ call(f);
+}
+
+#[inline]
+fn call<F: FnOnce()>(f: F) {
+ f();
+}
+
+#[inline]
+fn f() {
+ call(f);
+}
+ // MIR for `two` after Inline
fn two() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/inline-cycle.rs:+0:10: +0:10
- let _1: (); // in scope 0 at $DIR/inline-cycle.rs:+1:5: +1:12
-+ let mut _2: fn() {f}; // in scope 0 at $DIR/inline-cycle.rs:+1:5: +1:12
-+ scope 1 (inlined call::<fn() {f}>) { // at $DIR/inline-cycle.rs:49:5: 49:12
-+ debug f => _2; // in scope 1 at $DIR/inline-cycle.rs:53:22: 53:23
-+ let _3: (); // in scope 1 at $DIR/inline-cycle.rs:54:5: 54:8
-+ let mut _4: fn() {f}; // in scope 1 at $DIR/inline-cycle.rs:54:5: 54:6
-+ let mut _5: (); // in scope 1 at $DIR/inline-cycle.rs:54:5: 54:8
-+ scope 2 (inlined <fn() {f} as FnOnce<()>>::call_once - shim(fn() {f})) { // at $DIR/inline-cycle.rs:54:5: 54:8
+ let mut _0: (); // return place in scope 0 at $DIR/inline_cycle.rs:+0:10: +0:10
+ let _1: (); // in scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12
++ let mut _2: fn() {f}; // in scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12
++ scope 1 (inlined call::<fn() {f}>) { // at $DIR/inline_cycle.rs:49:5: 49:12
++ debug f => _2; // in scope 1 at $DIR/inline_cycle.rs:53:22: 53:23
++ let _3: (); // in scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
++ let mut _4: fn() {f}; // in scope 1 at $DIR/inline_cycle.rs:54:5: 54:6
++ let mut _5: (); // in scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
++ scope 2 (inlined <fn() {f} as FnOnce<()>>::call_once - shim(fn() {f})) { // at $DIR/inline_cycle.rs:54:5: 54:8
+ scope 3 (inlined f) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL
-+ let _6: (); // in scope 3 at $DIR/inline-cycle.rs:59:5: 59:12
++ let _6: (); // in scope 3 at $DIR/inline_cycle.rs:59:5: 59:12
+ }
+ }
+ }
bb0: {
- StorageLive(_1); // scope 0 at $DIR/inline-cycle.rs:+1:5: +1:12
-- _1 = call::<fn() {f}>(f) -> bb1; // scope 0 at $DIR/inline-cycle.rs:+1:5: +1:12
-+ StorageLive(_2); // scope 0 at $DIR/inline-cycle.rs:+1:5: +1:12
-+ _2 = f; // scope 0 at $DIR/inline-cycle.rs:+1:5: +1:12
+ StorageLive(_1); // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12
+- _1 = call::<fn() {f}>(f) -> bb1; // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12
++ StorageLive(_2); // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12
++ _2 = f; // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12
// mir::Constant
-- // + span: $DIR/inline-cycle.rs:49:5: 49:9
-+ // + span: $DIR/inline-cycle.rs:49:10: 49:11
+- // + span: $DIR/inline_cycle.rs:49:5: 49:9
++ // + span: $DIR/inline_cycle.rs:49:10: 49:11
+ // + literal: Const { ty: fn() {f}, val: Value(<ZST>) }
-+ StorageLive(_3); // scope 1 at $DIR/inline-cycle.rs:54:5: 54:8
-+ StorageLive(_4); // scope 1 at $DIR/inline-cycle.rs:54:5: 54:6
-+ _4 = move _2; // scope 1 at $DIR/inline-cycle.rs:54:5: 54:6
-+ StorageLive(_5); // scope 1 at $DIR/inline-cycle.rs:54:5: 54:8
-+ StorageLive(_6); // scope 3 at $DIR/inline-cycle.rs:59:5: 59:12
-+ _6 = call::<fn() {f}>(f) -> bb1; // scope 3 at $DIR/inline-cycle.rs:59:5: 59:12
++ StorageLive(_3); // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
++ StorageLive(_4); // scope 1 at $DIR/inline_cycle.rs:54:5: 54:6
++ _4 = move _2; // scope 1 at $DIR/inline_cycle.rs:54:5: 54:6
++ StorageLive(_5); // scope 1 at $DIR/inline_cycle.rs:54:5: 54:8
++ StorageLive(_6); // scope 3 at $DIR/inline_cycle.rs:59:5: 59:12
++ _6 = call::<fn() {f}>(f) -> bb1; // scope 3 at $DIR/inline_cycle.rs:59:5: 59:12
+ // mir::Constant
-+ // + span: $DIR/inline-cycle.rs:59:5: 59:9
++ // + span: $DIR/inline_cycle.rs:59:5: 59:9
// + literal: Const { ty: fn(fn() {f}) {call::<fn() {f}>}, val: Value(<ZST>) }
// mir::Constant
-- // + span: $DIR/inline-cycle.rs:49:10: 49:11
-+ // + span: $DIR/inline-cycle.rs:59:10: 59:11
+- // + span: $DIR/inline_cycle.rs:49:10: 49:11
++ // + span: $DIR/inline_cycle.rs:59:10: 59:11
// + literal: Const { ty: fn() {f}, val: Value(<ZST>) }
}
bb1: {
-+ StorageDead(_6); // scope 3 at $DIR/inline-cycle.rs:59:12: 59:13
-+ StorageDead(_5); // scope 1 at $DIR/inline-cycle.rs:54:7: 54:8
-+ StorageDead(_4); // scope 1 at $DIR/inline-cycle.rs:54:7: 54:8
-+ StorageDead(_3); // scope 1 at $DIR/inline-cycle.rs:54:8: 54:9
-+ StorageDead(_2); // scope 0 at $DIR/inline-cycle.rs:+1:5: +1:12
- StorageDead(_1); // scope 0 at $DIR/inline-cycle.rs:+1:12: +1:13
- _0 = const (); // scope 0 at $DIR/inline-cycle.rs:+0:10: +2:2
- return; // scope 0 at $DIR/inline-cycle.rs:+2:2: +2:2
++ StorageDead(_6); // scope 3 at $DIR/inline_cycle.rs:59:12: 59:13
++ StorageDead(_5); // scope 1 at $DIR/inline_cycle.rs:54:7: 54:8
++ StorageDead(_4); // scope 1 at $DIR/inline_cycle.rs:54:7: 54:8
++ StorageDead(_3); // scope 1 at $DIR/inline_cycle.rs:54:8: 54:9
++ StorageDead(_2); // scope 0 at $DIR/inline_cycle.rs:+1:5: +1:12
+ StorageDead(_1); // scope 0 at $DIR/inline_cycle.rs:+1:12: +1:13
+ _0 = const (); // scope 0 at $DIR/inline_cycle.rs:+0:10: +2:2
+ return; // scope 0 at $DIR/inline_cycle.rs:+2:2: +2:2
}
}
+ // MIR for `main` after Inline
fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/inline-cycle-generic.rs:+0:11: +0:11
- let _1: (); // in scope 0 at $DIR/inline-cycle-generic.rs:+1:5: +1:24
-+ scope 1 (inlined <C as Call>::call) { // at $DIR/inline-cycle-generic.rs:9:5: 9:24
-+ scope 2 (inlined <B<A> as Call>::call) { // at $DIR/inline-cycle-generic.rs:38:9: 38:31
-+ scope 3 (inlined <A as Call>::call) { // at $DIR/inline-cycle-generic.rs:31:9: 31:28
-+ scope 4 (inlined <B<C> as Call>::call) { // at $DIR/inline-cycle-generic.rs:23:9: 23:31
+ let mut _0: (); // return place in scope 0 at $DIR/inline_cycle_generic.rs:+0:11: +0:11
+ let _1: (); // in scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
++ scope 1 (inlined <C as Call>::call) { // at $DIR/inline_cycle_generic.rs:9:5: 9:24
++ scope 2 (inlined <B<A> as Call>::call) { // at $DIR/inline_cycle_generic.rs:38:9: 38:31
++ scope 3 (inlined <A as Call>::call) { // at $DIR/inline_cycle_generic.rs:31:9: 31:28
++ scope 4 (inlined <B<C> as Call>::call) { // at $DIR/inline_cycle_generic.rs:23:9: 23:31
+ }
+ }
+ }
+ }
bb0: {
- StorageLive(_1); // scope 0 at $DIR/inline-cycle-generic.rs:+1:5: +1:24
-- _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline-cycle-generic.rs:+1:5: +1:24
-+ _1 = <C as Call>::call() -> bb1; // scope 4 at $DIR/inline-cycle-generic.rs:31:9: 31:28
+ StorageLive(_1); // scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
+- _1 = <C as Call>::call() -> bb1; // scope 0 at $DIR/inline_cycle_generic.rs:+1:5: +1:24
++ _1 = <C as Call>::call() -> bb1; // scope 4 at $DIR/inline_cycle_generic.rs:31:9: 31:28
// mir::Constant
-- // + span: $DIR/inline-cycle-generic.rs:9:5: 9:22
-+ // + span: $DIR/inline-cycle-generic.rs:31:9: 31:26
+- // + span: $DIR/inline_cycle_generic.rs:9:5: 9:22
++ // + span: $DIR/inline_cycle_generic.rs:31:9: 31:26
// + literal: Const { ty: fn() {<C as Call>::call}, val: Value(<ZST>) }
}
bb1: {
- StorageDead(_1); // scope 0 at $DIR/inline-cycle-generic.rs:+1:24: +1:25
- _0 = const (); // scope 0 at $DIR/inline-cycle-generic.rs:+0:11: +2:2
- return; // scope 0 at $DIR/inline-cycle-generic.rs:+2:2: +2:2
+ StorageDead(_1); // scope 0 at $DIR/inline_cycle_generic.rs:+1:24: +1:25
+ _0 = const (); // scope 0 at $DIR/inline_cycle_generic.rs:+0:11: +2:2
+ return; // scope 0 at $DIR/inline_cycle_generic.rs:+2:2: +2:2
}
}
--- /dev/null
+// Check that inliner handles various forms of recursion and doesn't fall into
+// an infinite inlining cycle. The particular outcome of inlining is not
+// crucial otherwise.
+//
+// Regression test for issue #78573.
+
+// EMIT_MIR inline_cycle_generic.main.Inline.diff
+fn main() {
+ <C as Call>::call();
+}
+
+pub trait Call {
+ fn call();
+}
+
+pub struct A;
+pub struct B<T>(T);
+pub struct C;
+
+impl Call for A {
+ #[inline]
+ fn call() {
+ <B<C> as Call>::call()
+ }
+}
+
+
+impl<T: Call> Call for B<T> {
+ #[inline]
+ fn call() {
+ <T as Call>::call()
+ }
+}
+
+impl Call for C {
+ #[inline]
+ fn call() {
+ <B<A> as Call>::call()
+ }
+}
+ // MIR for `f` after Inline
fn f() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/inline-diverging.rs:+0:12: +0:12
- let mut _1: !; // in scope 0 at $DIR/inline-diverging.rs:+0:12: +2:2
- let _2: !; // in scope 0 at $DIR/inline-diverging.rs:+1:5: +1:12
-+ scope 1 (inlined sleep) { // at $DIR/inline-diverging.rs:8:5: 8:12
+ let mut _0: (); // return place in scope 0 at $DIR/inline_diverging.rs:+0:12: +0:12
+ let mut _1: !; // in scope 0 at $DIR/inline_diverging.rs:+0:12: +2:2
+ let _2: !; // in scope 0 at $DIR/inline_diverging.rs:+1:5: +1:12
++ scope 1 (inlined sleep) { // at $DIR/inline_diverging.rs:8:5: 8:12
+ }
bb0: {
- StorageLive(_2); // scope 0 at $DIR/inline-diverging.rs:+1:5: +1:12
-- _2 = sleep(); // scope 0 at $DIR/inline-diverging.rs:+1:5: +1:12
+ StorageLive(_2); // scope 0 at $DIR/inline_diverging.rs:+1:5: +1:12
+- _2 = sleep(); // scope 0 at $DIR/inline_diverging.rs:+1:5: +1:12
- // mir::Constant
-- // + span: $DIR/inline-diverging.rs:8:5: 8:10
+- // + span: $DIR/inline_diverging.rs:8:5: 8:10
- // + literal: Const { ty: fn() -> ! {sleep}, val: Value(<ZST>) }
-+ goto -> bb1; // scope 0 at $DIR/inline-diverging.rs:+1:5: +1:12
++ goto -> bb1; // scope 0 at $DIR/inline_diverging.rs:+1:5: +1:12
+ }
+
+ bb1: {
-+ goto -> bb1; // scope 1 at $DIR/inline-diverging.rs:39:5: 39:12
++ goto -> bb1; // scope 1 at $DIR/inline_diverging.rs:39:5: 39:12
}
}
+ // MIR for `g` after Inline
fn g(_1: i32) -> u32 {
- debug i => _1; // in scope 0 at $DIR/inline-diverging.rs:+0:10: +0:11
- let mut _0: u32; // return place in scope 0 at $DIR/inline-diverging.rs:+0:21: +0:24
- let mut _2: bool; // in scope 0 at $DIR/inline-diverging.rs:+1:8: +1:13
- let mut _3: i32; // in scope 0 at $DIR/inline-diverging.rs:+1:8: +1:9
- let mut _4: i32; // in scope 0 at $DIR/inline-diverging.rs:+2:9: +2:10
- let mut _5: !; // in scope 0 at $DIR/inline-diverging.rs:+3:12: +5:6
- let _6: !; // in scope 0 at $DIR/inline-diverging.rs:+4:9: +4:16
-+ scope 1 (inlined panic) { // at $DIR/inline-diverging.rs:16:9: 16:16
+ debug i => _1; // in scope 0 at $DIR/inline_diverging.rs:+0:10: +0:11
+ let mut _0: u32; // return place in scope 0 at $DIR/inline_diverging.rs:+0:21: +0:24
+ let mut _2: bool; // in scope 0 at $DIR/inline_diverging.rs:+1:8: +1:13
+ let mut _3: i32; // in scope 0 at $DIR/inline_diverging.rs:+1:8: +1:9
+ let mut _4: i32; // in scope 0 at $DIR/inline_diverging.rs:+2:9: +2:10
+ let mut _5: !; // in scope 0 at $DIR/inline_diverging.rs:+3:12: +5:6
+ let _6: !; // in scope 0 at $DIR/inline_diverging.rs:+4:9: +4:16
++ scope 1 (inlined panic) { // at $DIR/inline_diverging.rs:16:9: 16:16
+ let mut _7: !; // in scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL
+ }
bb0: {
- StorageLive(_2); // scope 0 at $DIR/inline-diverging.rs:+1:8: +1:13
- StorageLive(_3); // scope 0 at $DIR/inline-diverging.rs:+1:8: +1:9
- _3 = _1; // scope 0 at $DIR/inline-diverging.rs:+1:8: +1:9
- _2 = Gt(move _3, const 0_i32); // scope 0 at $DIR/inline-diverging.rs:+1:8: +1:13
- StorageDead(_3); // scope 0 at $DIR/inline-diverging.rs:+1:12: +1:13
- switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/inline-diverging.rs:+1:8: +1:13
+ StorageLive(_2); // scope 0 at $DIR/inline_diverging.rs:+1:8: +1:13
+ StorageLive(_3); // scope 0 at $DIR/inline_diverging.rs:+1:8: +1:9
+ _3 = _1; // scope 0 at $DIR/inline_diverging.rs:+1:8: +1:9
+ _2 = Gt(move _3, const 0_i32); // scope 0 at $DIR/inline_diverging.rs:+1:8: +1:13
+ StorageDead(_3); // scope 0 at $DIR/inline_diverging.rs:+1:12: +1:13
+ switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/inline_diverging.rs:+1:8: +1:13
}
bb1: {
- StorageLive(_4); // scope 0 at $DIR/inline-diverging.rs:+2:9: +2:10
- _4 = _1; // scope 0 at $DIR/inline-diverging.rs:+2:9: +2:10
- _0 = move _4 as u32 (IntToInt); // scope 0 at $DIR/inline-diverging.rs:+2:9: +2:17
- StorageDead(_4); // scope 0 at $DIR/inline-diverging.rs:+2:16: +2:17
- StorageDead(_2); // scope 0 at $DIR/inline-diverging.rs:+5:5: +5:6
- return; // scope 0 at $DIR/inline-diverging.rs:+6:2: +6:2
+ StorageLive(_4); // scope 0 at $DIR/inline_diverging.rs:+2:9: +2:10
+ _4 = _1; // scope 0 at $DIR/inline_diverging.rs:+2:9: +2:10
+ _0 = move _4 as u32 (IntToInt); // scope 0 at $DIR/inline_diverging.rs:+2:9: +2:17
+ StorageDead(_4); // scope 0 at $DIR/inline_diverging.rs:+2:16: +2:17
+ StorageDead(_2); // scope 0 at $DIR/inline_diverging.rs:+5:5: +5:6
+ return; // scope 0 at $DIR/inline_diverging.rs:+6:2: +6:2
}
bb2: {
- StorageLive(_6); // scope 0 at $DIR/inline-diverging.rs:+4:9: +4:16
-- _6 = panic(); // scope 0 at $DIR/inline-diverging.rs:+4:9: +4:16
+ StorageLive(_6); // scope 0 at $DIR/inline_diverging.rs:+4:9: +4:16
+- _6 = panic(); // scope 0 at $DIR/inline_diverging.rs:+4:9: +4:16
+ StorageLive(_7); // scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL
+ _7 = begin_panic::<&str>(const "explicit panic"); // scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL
// mir::Constant
-- // + span: $DIR/inline-diverging.rs:16:9: 16:14
+- // + span: $DIR/inline_diverging.rs:16:9: 16:14
- // + literal: Const { ty: fn() -> ! {panic}, val: Value(<ZST>) }
+ // + span: $SRC_DIR/std/src/panic.rs:LL:COL
+ // + literal: Const { ty: fn(&str) -> ! {begin_panic::<&str>}, val: Value(<ZST>) }
+ // MIR for `h` after Inline
fn h() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/inline-diverging.rs:+0:12: +0:12
- let _1: (!, !); // in scope 0 at $DIR/inline-diverging.rs:+1:5: +1:22
-+ let mut _2: fn() -> ! {sleep}; // in scope 0 at $DIR/inline-diverging.rs:+1:5: +1:22
-+ scope 1 (inlined call_twice::<!, fn() -> ! {sleep}>) { // at $DIR/inline-diverging.rs:22:5: 22:22
-+ debug f => _2; // in scope 1 at $DIR/inline-diverging.rs:26:36: 26:37
-+ let _3: !; // in scope 1 at $DIR/inline-diverging.rs:27:9: 27:10
-+ let mut _4: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
-+ let mut _5: (); // in scope 1 at $DIR/inline-diverging.rs:27:13: 27:16
-+ let mut _7: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline-diverging.rs:28:13: 28:14
-+ let mut _8: (); // in scope 1 at $DIR/inline-diverging.rs:28:13: 28:16
-+ let mut _9: !; // in scope 1 at $DIR/inline-diverging.rs:29:6: 29:7
-+ let mut _10: !; // in scope 1 at $DIR/inline-diverging.rs:29:9: 29:10
+ let mut _0: (); // return place in scope 0 at $DIR/inline_diverging.rs:+0:12: +0:12
+ let _1: (!, !); // in scope 0 at $DIR/inline_diverging.rs:+1:5: +1:22
++ let mut _2: fn() -> ! {sleep}; // in scope 0 at $DIR/inline_diverging.rs:+1:5: +1:22
++ scope 1 (inlined call_twice::<!, fn() -> ! {sleep}>) { // at $DIR/inline_diverging.rs:22:5: 22:22
++ debug f => _2; // in scope 1 at $DIR/inline_diverging.rs:26:36: 26:37
++ let _3: !; // in scope 1 at $DIR/inline_diverging.rs:27:9: 27:10
++ let mut _4: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
++ let mut _5: (); // in scope 1 at $DIR/inline_diverging.rs:27:13: 27:16
++ let mut _7: &fn() -> ! {sleep}; // in scope 1 at $DIR/inline_diverging.rs:28:13: 28:14
++ let mut _8: (); // in scope 1 at $DIR/inline_diverging.rs:28:13: 28:16
++ let mut _9: !; // in scope 1 at $DIR/inline_diverging.rs:29:6: 29:7
++ let mut _10: !; // in scope 1 at $DIR/inline_diverging.rs:29:9: 29:10
+ scope 2 {
-+ debug a => _3; // in scope 2 at $DIR/inline-diverging.rs:27:9: 27:10
-+ let _6: !; // in scope 2 at $DIR/inline-diverging.rs:28:9: 28:10
++ debug a => _3; // in scope 2 at $DIR/inline_diverging.rs:27:9: 27:10
++ let _6: !; // in scope 2 at $DIR/inline_diverging.rs:28:9: 28:10
+ scope 3 {
-+ debug b => _6; // in scope 3 at $DIR/inline-diverging.rs:28:9: 28:10
++ debug b => _6; // in scope 3 at $DIR/inline_diverging.rs:28:9: 28:10
+ }
-+ scope 6 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline-diverging.rs:28:13: 28:16
++ scope 6 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline_diverging.rs:28:13: 28:16
+ scope 7 (inlined sleep) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL
+ }
+ }
+ }
-+ scope 4 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline-diverging.rs:27:13: 27:16
++ scope 4 (inlined <fn() -> ! {sleep} as Fn<()>>::call - shim(fn() -> ! {sleep})) { // at $DIR/inline_diverging.rs:27:13: 27:16
+ scope 5 (inlined sleep) { // at $SRC_DIR/core/src/ops/function.rs:LL:COL
+ }
+ }
+ }
bb0: {
- StorageLive(_1); // scope 0 at $DIR/inline-diverging.rs:+1:5: +1:22
-- _1 = call_twice::<!, fn() -> ! {sleep}>(sleep); // scope 0 at $DIR/inline-diverging.rs:+1:5: +1:22
-+ StorageLive(_2); // scope 0 at $DIR/inline-diverging.rs:+1:5: +1:22
-+ _2 = sleep; // scope 0 at $DIR/inline-diverging.rs:+1:5: +1:22
+ StorageLive(_1); // scope 0 at $DIR/inline_diverging.rs:+1:5: +1:22
+- _1 = call_twice::<!, fn() -> ! {sleep}>(sleep); // scope 0 at $DIR/inline_diverging.rs:+1:5: +1:22
++ StorageLive(_2); // scope 0 at $DIR/inline_diverging.rs:+1:5: +1:22
++ _2 = sleep; // scope 0 at $DIR/inline_diverging.rs:+1:5: +1:22
// mir::Constant
-- // + span: $DIR/inline-diverging.rs:22:5: 22:15
+- // + span: $DIR/inline_diverging.rs:22:5: 22:15
- // + literal: Const { ty: fn(fn() -> ! {sleep}) -> (!, !) {call_twice::<!, fn() -> ! {sleep}>}, val: Value(<ZST>) }
- // mir::Constant
- // + span: $DIR/inline-diverging.rs:22:16: 22:21
+ // + span: $DIR/inline_diverging.rs:22:16: 22:21
// + literal: Const { ty: fn() -> ! {sleep}, val: Value(<ZST>) }
-+ StorageLive(_3); // scope 1 at $DIR/inline-diverging.rs:27:9: 27:10
-+ StorageLive(_4); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
-+ _4 = &_2; // scope 1 at $DIR/inline-diverging.rs:27:13: 27:14
-+ StorageLive(_5); // scope 1 at $DIR/inline-diverging.rs:27:13: 27:16
-+ goto -> bb1; // scope 5 at $DIR/inline-diverging.rs:39:5: 39:12
++ StorageLive(_3); // scope 1 at $DIR/inline_diverging.rs:27:9: 27:10
++ StorageLive(_4); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
++ _4 = &_2; // scope 1 at $DIR/inline_diverging.rs:27:13: 27:14
++ StorageLive(_5); // scope 1 at $DIR/inline_diverging.rs:27:13: 27:16
++ goto -> bb1; // scope 5 at $DIR/inline_diverging.rs:39:5: 39:12
+ }
+
+ bb1: {
-+ goto -> bb1; // scope 5 at $DIR/inline-diverging.rs:39:5: 39:12
++ goto -> bb1; // scope 5 at $DIR/inline_diverging.rs:39:5: 39:12
}
}
--- /dev/null
+// Tests inlining of diverging calls.
+//
+// ignore-wasm32-bare compiled with panic=abort by default
+#![crate_type = "lib"]
+
+// EMIT_MIR inline_diverging.f.Inline.diff
+pub fn f() {
+ sleep();
+}
+
+// EMIT_MIR inline_diverging.g.Inline.diff
+pub fn g(i: i32) -> u32 {
+ if i > 0 {
+ i as u32
+ } else {
+ panic();
+ }
+}
+
+// EMIT_MIR inline_diverging.h.Inline.diff
+pub fn h() {
+ call_twice(sleep);
+}
+
+#[inline(always)]
+pub fn call_twice<R, F: Fn() -> R>(f: F) -> (R, R) {
+ let a = f();
+ let b = f();
+ (a, b)
+}
+
+#[inline(always)]
+fn panic() -> ! {
+ panic!();
+}
+
+#[inline(always)]
+fn sleep() -> ! {
+ loop {}
+}
+ // MIR for `main` after Inline
fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/inline-generator.rs:+0:11: +0:11
- let _1: std::ops::GeneratorState<i32, bool>; // in scope 0 at $DIR/inline-generator.rs:+1:9: +1:11
- let mut _2: std::pin::Pin<&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>; // in scope 0 at $DIR/inline-generator.rs:+1:14: +1:32
- let mut _3: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 0 at $DIR/inline-generator.rs:+1:23: +1:31
- let mut _4: [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 0 at $DIR/inline-generator.rs:+1:28: +1:31
-+ let mut _7: bool; // in scope 0 at $DIR/inline-generator.rs:+1:14: +1:46
+ let mut _0: (); // return place in scope 0 at $DIR/inline_generator.rs:+0:11: +0:11
+ let _1: std::ops::GeneratorState<i32, bool>; // in scope 0 at $DIR/inline_generator.rs:+1:9: +1:11
+ let mut _2: std::pin::Pin<&mut [generator@$DIR/inline_generator.rs:15:5: 15:8]>; // in scope 0 at $DIR/inline_generator.rs:+1:14: +1:32
+ let mut _3: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]; // in scope 0 at $DIR/inline_generator.rs:+1:23: +1:31
+ let mut _4: [generator@$DIR/inline_generator.rs:15:5: 15:8]; // in scope 0 at $DIR/inline_generator.rs:+1:28: +1:31
++ let mut _7: bool; // in scope 0 at $DIR/inline_generator.rs:+1:14: +1:46
scope 1 {
- debug _r => _1; // in scope 1 at $DIR/inline-generator.rs:+1:9: +1:11
+ debug _r => _1; // in scope 1 at $DIR/inline_generator.rs:+1:9: +1:11
}
-+ scope 2 (inlined g) { // at $DIR/inline-generator.rs:9:28: 9:31
++ scope 2 (inlined g) { // at $DIR/inline_generator.rs:9:28: 9:31
+ }
-+ scope 3 (inlined Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>::new) { // at $DIR/inline-generator.rs:9:14: 9:32
++ scope 3 (inlined Pin::<&mut [generator@$DIR/inline_generator.rs:15:5: 15:8]>::new) { // at $DIR/inline_generator.rs:9:14: 9:32
+ debug pointer => _3; // in scope 3 at $SRC_DIR/core/src/pin.rs:LL:COL
-+ let mut _5: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 3 at $SRC_DIR/core/src/pin.rs:LL:COL
++ let mut _5: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]; // in scope 3 at $SRC_DIR/core/src/pin.rs:LL:COL
+ scope 4 {
-+ scope 5 (inlined Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>::new_unchecked) { // at $SRC_DIR/core/src/pin.rs:LL:COL
++ scope 5 (inlined Pin::<&mut [generator@$DIR/inline_generator.rs:15:5: 15:8]>::new_unchecked) { // at $SRC_DIR/core/src/pin.rs:LL:COL
+ debug pointer => _5; // in scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
-+ let mut _6: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
++ let mut _6: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]; // in scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
+ }
+ }
+ }
-+ scope 6 (inlined g::{closure#0}) { // at $DIR/inline-generator.rs:9:14: 9:46
-+ debug a => _11; // in scope 6 at $DIR/inline-generator.rs:15:6: 15:7
-+ let mut _8: i32; // in scope 6 at $DIR/inline-generator.rs:15:17: 15:39
-+ let mut _9: bool; // in scope 6 at $DIR/inline-generator.rs:15:20: 15:21
-+ let mut _10: bool; // in scope 6 at $DIR/inline-generator.rs:15:9: 15:9
-+ let _11: bool; // in scope 6 at $DIR/inline-generator.rs:15:6: 15:7
-+ let mut _12: u32; // in scope 6 at $DIR/inline-generator.rs:15:5: 15:41
-+ let mut _13: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline-generator.rs:15:5: 15:41
-+ let mut _14: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline-generator.rs:15:5: 15:41
-+ let mut _15: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline-generator.rs:15:5: 15:41
++ scope 6 (inlined g::{closure#0}) { // at $DIR/inline_generator.rs:9:14: 9:46
++ debug a => _11; // in scope 6 at $DIR/inline_generator.rs:15:6: 15:7
++ let mut _8: i32; // in scope 6 at $DIR/inline_generator.rs:15:17: 15:39
++ let mut _9: bool; // in scope 6 at $DIR/inline_generator.rs:15:20: 15:21
++ let mut _10: bool; // in scope 6 at $DIR/inline_generator.rs:15:9: 15:9
++ let _11: bool; // in scope 6 at $DIR/inline_generator.rs:15:6: 15:7
++ let mut _12: u32; // in scope 6 at $DIR/inline_generator.rs:15:5: 15:41
++ let mut _13: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline_generator.rs:15:5: 15:41
++ let mut _14: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline_generator.rs:15:5: 15:41
++ let mut _15: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]; // in scope 6 at $DIR/inline_generator.rs:15:5: 15:41
+ }
bb0: {
- StorageLive(_1); // scope 0 at $DIR/inline-generator.rs:+1:9: +1:11
- StorageLive(_2); // scope 0 at $DIR/inline-generator.rs:+1:14: +1:32
- StorageLive(_3); // scope 0 at $DIR/inline-generator.rs:+1:23: +1:31
- StorageLive(_4); // scope 0 at $DIR/inline-generator.rs:+1:28: +1:31
-- _4 = g() -> bb1; // scope 0 at $DIR/inline-generator.rs:+1:28: +1:31
+ StorageLive(_1); // scope 0 at $DIR/inline_generator.rs:+1:9: +1:11
+ StorageLive(_2); // scope 0 at $DIR/inline_generator.rs:+1:14: +1:32
+ StorageLive(_3); // scope 0 at $DIR/inline_generator.rs:+1:23: +1:31
+ StorageLive(_4); // scope 0 at $DIR/inline_generator.rs:+1:28: +1:31
+- _4 = g() -> bb1; // scope 0 at $DIR/inline_generator.rs:+1:28: +1:31
- // mir::Constant
-- // + span: $DIR/inline-generator.rs:9:28: 9:29
+- // + span: $DIR/inline_generator.rs:9:28: 9:29
- // + literal: Const { ty: fn() -> impl Generator<bool> {g}, val: Value(<ZST>) }
- }
-
- bb1: {
-+ Deinit(_4); // scope 2 at $DIR/inline-generator.rs:15:5: 15:41
-+ discriminant(_4) = 0; // scope 2 at $DIR/inline-generator.rs:15:5: 15:41
- _3 = &mut _4; // scope 0 at $DIR/inline-generator.rs:+1:23: +1:31
-- _2 = Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>::new(move _3) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:+1:14: +1:32
++ Deinit(_4); // scope 2 at $DIR/inline_generator.rs:15:5: 15:41
++ discriminant(_4) = 0; // scope 2 at $DIR/inline_generator.rs:15:5: 15:41
+ _3 = &mut _4; // scope 0 at $DIR/inline_generator.rs:+1:23: +1:31
+- _2 = Pin::<&mut [generator@$DIR/inline_generator.rs:15:5: 15:8]>::new(move _3) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline_generator.rs:+1:14: +1:32
- // mir::Constant
-- // + span: $DIR/inline-generator.rs:9:14: 9:22
+- // + span: $DIR/inline_generator.rs:9:14: 9:22
- // + user_ty: UserType(0)
-- // + literal: Const { ty: fn(&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]) -> Pin<&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]> {Pin::<&mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>::new}, val: Value(<ZST>) }
+- // + literal: Const { ty: fn(&mut [generator@$DIR/inline_generator.rs:15:5: 15:8]) -> Pin<&mut [generator@$DIR/inline_generator.rs:15:5: 15:8]> {Pin::<&mut [generator@$DIR/inline_generator.rs:15:5: 15:8]>::new}, val: Value(<ZST>) }
- }
-
- bb2: {
+ StorageLive(_6); // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
+ _6 = move _5; // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
+ Deinit(_2); // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
-+ (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]) = move _6; // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
++ (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]) = move _6; // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
+ StorageDead(_6); // scope 5 at $SRC_DIR/core/src/pin.rs:LL:COL
+ StorageDead(_5); // scope 4 at $SRC_DIR/core/src/pin.rs:LL:COL
- StorageDead(_3); // scope 0 at $DIR/inline-generator.rs:+1:31: +1:32
-- _1 = <[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator<bool>>::resume(move _2, const false) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46
+ StorageDead(_3); // scope 0 at $DIR/inline_generator.rs:+1:31: +1:32
+- _1 = <[generator@$DIR/inline_generator.rs:15:5: 15:8] as Generator<bool>>::resume(move _2, const false) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline_generator.rs:+1:14: +1:46
- // mir::Constant
-- // + span: $DIR/inline-generator.rs:9:33: 9:39
-- // + literal: Const { ty: for<'a> fn(Pin<&'a mut [generator@$DIR/inline-generator.rs:15:5: 15:8]>, bool) -> GeneratorState<<[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator<bool>>::Yield, <[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator<bool>>::Return> {<[generator@$DIR/inline-generator.rs:15:5: 15:8] as Generator<bool>>::resume}, val: Value(<ZST>) }
-+ StorageLive(_7); // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46
-+ _7 = const false; // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46
-+ StorageLive(_10); // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46
-+ StorageLive(_11); // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46
-+ _13 = deref_copy (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline-generator.rs:15:5: 15:41
-+ _12 = discriminant((*_13)); // scope 6 at $DIR/inline-generator.rs:15:5: 15:41
-+ switchInt(move _12) -> [0_u32: bb3, 1_u32: bb8, 3_u32: bb7, otherwise: bb9]; // scope 6 at $DIR/inline-generator.rs:15:5: 15:41
+- // + span: $DIR/inline_generator.rs:9:33: 9:39
+- // + literal: Const { ty: for<'a> fn(Pin<&'a mut [generator@$DIR/inline_generator.rs:15:5: 15:8]>, bool) -> GeneratorState<<[generator@$DIR/inline_generator.rs:15:5: 15:8] as Generator<bool>>::Yield, <[generator@$DIR/inline_generator.rs:15:5: 15:8] as Generator<bool>>::Return> {<[generator@$DIR/inline_generator.rs:15:5: 15:8] as Generator<bool>>::resume}, val: Value(<ZST>) }
++ StorageLive(_7); // scope 0 at $DIR/inline_generator.rs:+1:14: +1:46
++ _7 = const false; // scope 0 at $DIR/inline_generator.rs:+1:14: +1:46
++ StorageLive(_10); // scope 0 at $DIR/inline_generator.rs:+1:14: +1:46
++ StorageLive(_11); // scope 0 at $DIR/inline_generator.rs:+1:14: +1:46
++ _13 = deref_copy (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
++ _12 = discriminant((*_13)); // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
++ switchInt(move _12) -> [0_u32: bb3, 1_u32: bb8, 3_u32: bb7, otherwise: bb9]; // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
}
- bb3: {
+ bb1: {
-+ StorageDead(_11); // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46
-+ StorageDead(_10); // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46
-+ StorageDead(_7); // scope 0 at $DIR/inline-generator.rs:+1:14: +1:46
- StorageDead(_2); // scope 0 at $DIR/inline-generator.rs:+1:45: +1:46
- StorageDead(_4); // scope 0 at $DIR/inline-generator.rs:+1:46: +1:47
- _0 = const (); // scope 0 at $DIR/inline-generator.rs:+0:11: +2:2
- StorageDead(_1); // scope 0 at $DIR/inline-generator.rs:+2:1: +2:2
- return; // scope 0 at $DIR/inline-generator.rs:+2:2: +2:2
++ StorageDead(_11); // scope 0 at $DIR/inline_generator.rs:+1:14: +1:46
++ StorageDead(_10); // scope 0 at $DIR/inline_generator.rs:+1:14: +1:46
++ StorageDead(_7); // scope 0 at $DIR/inline_generator.rs:+1:14: +1:46
+ StorageDead(_2); // scope 0 at $DIR/inline_generator.rs:+1:45: +1:46
+ StorageDead(_4); // scope 0 at $DIR/inline_generator.rs:+1:46: +1:47
+ _0 = const (); // scope 0 at $DIR/inline_generator.rs:+0:11: +2:2
+ StorageDead(_1); // scope 0 at $DIR/inline_generator.rs:+2:1: +2:2
+ return; // scope 0 at $DIR/inline_generator.rs:+2:2: +2:2
}
- bb4 (cleanup): {
+ bb2 (cleanup): {
- resume; // scope 0 at $DIR/inline-generator.rs:+0:1: +2:2
+ resume; // scope 0 at $DIR/inline_generator.rs:+0:1: +2:2
+ }
+
+ bb3: {
-+ _11 = move _7; // scope 6 at $DIR/inline-generator.rs:15:5: 15:41
-+ StorageLive(_8); // scope 6 at $DIR/inline-generator.rs:15:17: 15:39
-+ StorageLive(_9); // scope 6 at $DIR/inline-generator.rs:15:20: 15:21
-+ _9 = _11; // scope 6 at $DIR/inline-generator.rs:15:20: 15:21
-+ switchInt(move _9) -> [false: bb5, otherwise: bb4]; // scope 6 at $DIR/inline-generator.rs:15:20: 15:21
++ _11 = move _7; // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
++ StorageLive(_8); // scope 6 at $DIR/inline_generator.rs:15:17: 15:39
++ StorageLive(_9); // scope 6 at $DIR/inline_generator.rs:15:20: 15:21
++ _9 = _11; // scope 6 at $DIR/inline_generator.rs:15:20: 15:21
++ switchInt(move _9) -> [false: bb5, otherwise: bb4]; // scope 6 at $DIR/inline_generator.rs:15:20: 15:21
+ }
+
+ bb4: {
-+ _8 = const 7_i32; // scope 6 at $DIR/inline-generator.rs:15:24: 15:25
-+ goto -> bb6; // scope 6 at $DIR/inline-generator.rs:15:17: 15:39
++ _8 = const 7_i32; // scope 6 at $DIR/inline_generator.rs:15:24: 15:25
++ goto -> bb6; // scope 6 at $DIR/inline_generator.rs:15:17: 15:39
+ }
+
+ bb5: {
-+ _8 = const 13_i32; // scope 6 at $DIR/inline-generator.rs:15:35: 15:37
-+ goto -> bb6; // scope 6 at $DIR/inline-generator.rs:15:17: 15:39
++ _8 = const 13_i32; // scope 6 at $DIR/inline_generator.rs:15:35: 15:37
++ goto -> bb6; // scope 6 at $DIR/inline_generator.rs:15:17: 15:39
+ }
+
+ bb6: {
-+ StorageDead(_9); // scope 6 at $DIR/inline-generator.rs:15:38: 15:39
-+ Deinit(_1); // scope 6 at $DIR/inline-generator.rs:15:11: 15:39
-+ ((_1 as Yielded).0: i32) = move _8; // scope 6 at $DIR/inline-generator.rs:15:11: 15:39
-+ discriminant(_1) = 0; // scope 6 at $DIR/inline-generator.rs:15:11: 15:39
-+ _14 = deref_copy (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline-generator.rs:15:11: 15:39
-+ discriminant((*_14)) = 3; // scope 6 at $DIR/inline-generator.rs:15:11: 15:39
-+ goto -> bb1; // scope 0 at $DIR/inline-generator.rs:15:11: 15:39
++ StorageDead(_9); // scope 6 at $DIR/inline_generator.rs:15:38: 15:39
++ Deinit(_1); // scope 6 at $DIR/inline_generator.rs:15:11: 15:39
++ ((_1 as Yielded).0: i32) = move _8; // scope 6 at $DIR/inline_generator.rs:15:11: 15:39
++ discriminant(_1) = 0; // scope 6 at $DIR/inline_generator.rs:15:11: 15:39
++ _14 = deref_copy (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline_generator.rs:15:11: 15:39
++ discriminant((*_14)) = 3; // scope 6 at $DIR/inline_generator.rs:15:11: 15:39
++ goto -> bb1; // scope 0 at $DIR/inline_generator.rs:15:11: 15:39
+ }
+
+ bb7: {
-+ StorageLive(_8); // scope 6 at $DIR/inline-generator.rs:15:5: 15:41
-+ _10 = move _7; // scope 6 at $DIR/inline-generator.rs:15:5: 15:41
-+ StorageDead(_8); // scope 6 at $DIR/inline-generator.rs:15:38: 15:39
-+ Deinit(_1); // scope 6 at $DIR/inline-generator.rs:15:41: 15:41
-+ ((_1 as Complete).0: bool) = move _10; // scope 6 at $DIR/inline-generator.rs:15:41: 15:41
-+ discriminant(_1) = 1; // scope 6 at $DIR/inline-generator.rs:15:41: 15:41
-+ _15 = deref_copy (_2.0: &mut [generator@$DIR/inline-generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline-generator.rs:15:41: 15:41
-+ discriminant((*_15)) = 1; // scope 6 at $DIR/inline-generator.rs:15:41: 15:41
-+ goto -> bb1; // scope 0 at $DIR/inline-generator.rs:15:41: 15:41
++ StorageLive(_8); // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
++ _10 = move _7; // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
++ StorageDead(_8); // scope 6 at $DIR/inline_generator.rs:15:38: 15:39
++ Deinit(_1); // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
++ ((_1 as Complete).0: bool) = move _10; // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
++ discriminant(_1) = 1; // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
++ _15 = deref_copy (_2.0: &mut [generator@$DIR/inline_generator.rs:15:5: 15:8]); // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
++ discriminant((*_15)) = 1; // scope 6 at $DIR/inline_generator.rs:15:41: 15:41
++ goto -> bb1; // scope 0 at $DIR/inline_generator.rs:15:41: 15:41
+ }
+
+ bb8: {
-+ assert(const false, "generator resumed after completion") -> [success: bb8, unwind: bb2]; // scope 6 at $DIR/inline-generator.rs:15:5: 15:41
++ assert(const false, "generator resumed after completion") -> [success: bb8, unwind: bb2]; // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
+ }
+
+ bb9: {
-+ unreachable; // scope 6 at $DIR/inline-generator.rs:15:5: 15:41
++ unreachable; // scope 6 at $DIR/inline_generator.rs:15:5: 15:41
}
}
--- /dev/null
+// ignore-wasm32-bare compiled with panic=abort by default
+#![feature(generators, generator_trait)]
+
+use std::ops::Generator;
+use std::pin::Pin;
+
+// EMIT_MIR inline_generator.main.Inline.diff
+fn main() {
+ let _r = Pin::new(&mut g()).resume(false);
+}
+
+#[inline(always)]
+pub fn g() -> impl Generator<bool> {
+ #[inline(always)]
+ |a| { yield if a { 7 } else { 13 } }
+}
+ // MIR for `default` after Inline
fn default() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/inline-instruction-set.rs:+0:18: +0:18
- let _1: (); // in scope 0 at $DIR/inline-instruction-set.rs:+1:5: +1:26
- let _2: (); // in scope 0 at $DIR/inline-instruction-set.rs:+2:5: +2:26
- let _3: (); // in scope 0 at $DIR/inline-instruction-set.rs:+3:5: +3:30
-+ scope 1 (inlined instruction_set_default) { // at $DIR/inline-instruction-set.rs:53:5: 53:30
+ let mut _0: (); // return place in scope 0 at $DIR/inline_instruction_set.rs:+0:18: +0:18
+ let _1: (); // in scope 0 at $DIR/inline_instruction_set.rs:+1:5: +1:26
+ let _2: (); // in scope 0 at $DIR/inline_instruction_set.rs:+2:5: +2:26
+ let _3: (); // in scope 0 at $DIR/inline_instruction_set.rs:+3:5: +3:30
++ scope 1 (inlined instruction_set_default) { // at $DIR/inline_instruction_set.rs:53:5: 53:30
+ }
bb0: {
- StorageLive(_1); // scope 0 at $DIR/inline-instruction-set.rs:+1:5: +1:26
- _1 = instruction_set_a32() -> bb1; // scope 0 at $DIR/inline-instruction-set.rs:+1:5: +1:26
+ StorageLive(_1); // scope 0 at $DIR/inline_instruction_set.rs:+1:5: +1:26
+ _1 = instruction_set_a32() -> bb1; // scope 0 at $DIR/inline_instruction_set.rs:+1:5: +1:26
// mir::Constant
- // + span: $DIR/inline-instruction-set.rs:51:5: 51:24
+ // + span: $DIR/inline_instruction_set.rs:51:5: 51:24
// + literal: Const { ty: fn() {instruction_set_a32}, val: Value(<ZST>) }
}
bb1: {
- StorageDead(_1); // scope 0 at $DIR/inline-instruction-set.rs:+1:26: +1:27
- StorageLive(_2); // scope 0 at $DIR/inline-instruction-set.rs:+2:5: +2:26
- _2 = instruction_set_t32() -> bb2; // scope 0 at $DIR/inline-instruction-set.rs:+2:5: +2:26
+ StorageDead(_1); // scope 0 at $DIR/inline_instruction_set.rs:+1:26: +1:27
+ StorageLive(_2); // scope 0 at $DIR/inline_instruction_set.rs:+2:5: +2:26
+ _2 = instruction_set_t32() -> bb2; // scope 0 at $DIR/inline_instruction_set.rs:+2:5: +2:26
// mir::Constant
- // + span: $DIR/inline-instruction-set.rs:52:5: 52:24
+ // + span: $DIR/inline_instruction_set.rs:52:5: 52:24
// + literal: Const { ty: fn() {instruction_set_t32}, val: Value(<ZST>) }
}
bb2: {
- StorageDead(_2); // scope 0 at $DIR/inline-instruction-set.rs:+2:26: +2:27
- StorageLive(_3); // scope 0 at $DIR/inline-instruction-set.rs:+3:5: +3:30
-- _3 = instruction_set_default() -> bb3; // scope 0 at $DIR/inline-instruction-set.rs:+3:5: +3:30
+ StorageDead(_2); // scope 0 at $DIR/inline_instruction_set.rs:+2:26: +2:27
+ StorageLive(_3); // scope 0 at $DIR/inline_instruction_set.rs:+3:5: +3:30
+- _3 = instruction_set_default() -> bb3; // scope 0 at $DIR/inline_instruction_set.rs:+3:5: +3:30
- // mir::Constant
-- // + span: $DIR/inline-instruction-set.rs:53:5: 53:28
+- // + span: $DIR/inline_instruction_set.rs:53:5: 53:28
- // + literal: Const { ty: fn() {instruction_set_default}, val: Value(<ZST>) }
- }
-
- bb3: {
- StorageDead(_3); // scope 0 at $DIR/inline-instruction-set.rs:+3:30: +3:31
- _0 = const (); // scope 0 at $DIR/inline-instruction-set.rs:+0:18: +4:2
- return; // scope 0 at $DIR/inline-instruction-set.rs:+4:2: +4:2
+ StorageDead(_3); // scope 0 at $DIR/inline_instruction_set.rs:+3:30: +3:31
+ _0 = const (); // scope 0 at $DIR/inline_instruction_set.rs:+0:18: +4:2
+ return; // scope 0 at $DIR/inline_instruction_set.rs:+4:2: +4:2
}
}
--- /dev/null
+// Checks that only functions with the compatible instruction_set attributes are inlined.
+//
+// compile-flags: --target thumbv4t-none-eabi
+// needs-llvm-components: arm
+
+#![crate_type = "lib"]
+#![feature(rustc_attrs)]
+#![feature(no_core, lang_items)]
+#![feature(isa_attribute)]
+#![no_core]
+
+#[rustc_builtin_macro]
+#[macro_export]
+macro_rules! asm {
+ ("assembly template",
+ $(operands,)*
+ $(options($(option),*))?
+ ) => {
+ /* compiler built-in */
+ };
+}
+
+#[lang = "sized"]
+trait Sized {}
+#[lang = "copy"]
+trait Copy {}
+
+#[instruction_set(arm::a32)]
+#[inline]
+fn instruction_set_a32() {}
+
+#[instruction_set(arm::t32)]
+#[inline]
+fn instruction_set_t32() {}
+
+#[inline]
+fn instruction_set_default() {}
+
+// EMIT_MIR inline_instruction_set.t32.Inline.diff
+#[instruction_set(arm::t32)]
+pub fn t32() {
+ instruction_set_a32();
+ instruction_set_t32();
+ // The default instruction set is currently
+ // conservatively assumed to be incompatible.
+ instruction_set_default();
+}
+
+// EMIT_MIR inline_instruction_set.default.Inline.diff
+pub fn default() {
+ instruction_set_a32();
+ instruction_set_t32();
+ instruction_set_default();
+}
+ // MIR for `t32` after Inline
fn t32() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/inline-instruction-set.rs:+0:14: +0:14
- let _1: (); // in scope 0 at $DIR/inline-instruction-set.rs:+1:5: +1:26
- let _2: (); // in scope 0 at $DIR/inline-instruction-set.rs:+2:5: +2:26
- let _3: (); // in scope 0 at $DIR/inline-instruction-set.rs:+5:5: +5:30
-+ scope 1 (inlined instruction_set_t32) { // at $DIR/inline-instruction-set.rs:43:5: 43:26
+ let mut _0: (); // return place in scope 0 at $DIR/inline_instruction_set.rs:+0:14: +0:14
+ let _1: (); // in scope 0 at $DIR/inline_instruction_set.rs:+1:5: +1:26
+ let _2: (); // in scope 0 at $DIR/inline_instruction_set.rs:+2:5: +2:26
+ let _3: (); // in scope 0 at $DIR/inline_instruction_set.rs:+5:5: +5:30
++ scope 1 (inlined instruction_set_t32) { // at $DIR/inline_instruction_set.rs:43:5: 43:26
+ }
bb0: {
- StorageLive(_1); // scope 0 at $DIR/inline-instruction-set.rs:+1:5: +1:26
- _1 = instruction_set_a32() -> bb1; // scope 0 at $DIR/inline-instruction-set.rs:+1:5: +1:26
+ StorageLive(_1); // scope 0 at $DIR/inline_instruction_set.rs:+1:5: +1:26
+ _1 = instruction_set_a32() -> bb1; // scope 0 at $DIR/inline_instruction_set.rs:+1:5: +1:26
// mir::Constant
- // + span: $DIR/inline-instruction-set.rs:42:5: 42:24
+ // + span: $DIR/inline_instruction_set.rs:42:5: 42:24
// + literal: Const { ty: fn() {instruction_set_a32}, val: Value(<ZST>) }
}
bb1: {
- StorageDead(_1); // scope 0 at $DIR/inline-instruction-set.rs:+1:26: +1:27
- StorageLive(_2); // scope 0 at $DIR/inline-instruction-set.rs:+2:5: +2:26
-- _2 = instruction_set_t32() -> bb2; // scope 0 at $DIR/inline-instruction-set.rs:+2:5: +2:26
+ StorageDead(_1); // scope 0 at $DIR/inline_instruction_set.rs:+1:26: +1:27
+ StorageLive(_2); // scope 0 at $DIR/inline_instruction_set.rs:+2:5: +2:26
+- _2 = instruction_set_t32() -> bb2; // scope 0 at $DIR/inline_instruction_set.rs:+2:5: +2:26
- // mir::Constant
-- // + span: $DIR/inline-instruction-set.rs:43:5: 43:24
+- // + span: $DIR/inline_instruction_set.rs:43:5: 43:24
- // + literal: Const { ty: fn() {instruction_set_t32}, val: Value(<ZST>) }
- }
-
- bb2: {
- StorageDead(_2); // scope 0 at $DIR/inline-instruction-set.rs:+2:26: +2:27
- StorageLive(_3); // scope 0 at $DIR/inline-instruction-set.rs:+5:5: +5:30
-- _3 = instruction_set_default() -> bb3; // scope 0 at $DIR/inline-instruction-set.rs:+5:5: +5:30
-+ _3 = instruction_set_default() -> bb2; // scope 0 at $DIR/inline-instruction-set.rs:+5:5: +5:30
+ StorageDead(_2); // scope 0 at $DIR/inline_instruction_set.rs:+2:26: +2:27
+ StorageLive(_3); // scope 0 at $DIR/inline_instruction_set.rs:+5:5: +5:30
+- _3 = instruction_set_default() -> bb3; // scope 0 at $DIR/inline_instruction_set.rs:+5:5: +5:30
++ _3 = instruction_set_default() -> bb2; // scope 0 at $DIR/inline_instruction_set.rs:+5:5: +5:30
// mir::Constant
- // + span: $DIR/inline-instruction-set.rs:46:5: 46:28
+ // + span: $DIR/inline_instruction_set.rs:46:5: 46:28
// + literal: Const { ty: fn() {instruction_set_default}, val: Value(<ZST>) }
}
- bb3: {
+ bb2: {
- StorageDead(_3); // scope 0 at $DIR/inline-instruction-set.rs:+5:30: +5:31
- _0 = const (); // scope 0 at $DIR/inline-instruction-set.rs:+0:14: +6:2
- return; // scope 0 at $DIR/inline-instruction-set.rs:+6:2: +6:2
+ StorageDead(_3); // scope 0 at $DIR/inline_instruction_set.rs:+5:30: +5:31
+ _0 = const (); // scope 0 at $DIR/inline_instruction_set.rs:+0:14: +6:2
+ return; // scope 0 at $DIR/inline_instruction_set.rs:+6:2: +6:2
}
}
+ // MIR for `main` after Inline
fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/inline-into-box-place.rs:+0:11: +0:11
- let _1: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:9: +1:11
- let mut _2: usize; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- let mut _3: usize; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- let mut _4: *mut u8; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- let mut _5: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- let mut _6: (); // in scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
- let mut _7: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
-+ let mut _8: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
+ let mut _0: (); // return place in scope 0 at $DIR/inline_into_box_place.rs:+0:11: +0:11
+ let _1: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline_into_box_place.rs:+1:9: +1:11
+ let mut _2: usize; // in scope 0 at $DIR/inline_into_box_place.rs:+1:29: +1:43
+ let mut _3: usize; // in scope 0 at $DIR/inline_into_box_place.rs:+1:29: +1:43
+ let mut _4: *mut u8; // in scope 0 at $DIR/inline_into_box_place.rs:+1:29: +1:43
+ let mut _5: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline_into_box_place.rs:+1:29: +1:43
+ let mut _6: (); // in scope 0 at $DIR/inline_into_box_place.rs:+1:42: +1:43
+ let mut _7: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline_into_box_place.rs:+1:29: +1:43
++ let mut _8: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
scope 1 {
- debug _x => _1; // in scope 1 at $DIR/inline-into-box-place.rs:+1:9: +1:11
+ debug _x => _1; // in scope 1 at $DIR/inline_into_box_place.rs:+1:9: +1:11
}
scope 2 {
}
-+ scope 3 (inlined Vec::<u32>::new) { // at $DIR/inline-into-box-place.rs:8:33: 8:43
++ scope 3 (inlined Vec::<u32>::new) { // at $DIR/inline_into_box_place.rs:8:33: 8:43
+ let mut _9: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+ }
bb0: {
- StorageLive(_1); // scope 0 at $DIR/inline-into-box-place.rs:+1:9: +1:11
- _2 = SizeOf(std::vec::Vec<u32>); // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- _3 = AlignOf(std::vec::Vec<u32>); // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:+1:29: +1:43
+ StorageLive(_1); // scope 0 at $DIR/inline_into_box_place.rs:+1:9: +1:11
+ _2 = SizeOf(std::vec::Vec<u32>); // scope 2 at $DIR/inline_into_box_place.rs:+1:29: +1:43
+ _3 = AlignOf(std::vec::Vec<u32>); // scope 2 at $DIR/inline_into_box_place.rs:+1:29: +1:43
+ _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline_into_box_place.rs:+1:29: +1:43
// mir::Constant
- // + span: $DIR/inline-into-box-place.rs:8:29: 8:43
+ // + span: $DIR/inline_into_box_place.rs:8:29: 8:43
// + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
}
bb1: {
- StorageLive(_5); // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- _5 = ShallowInitBox(move _4, std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- _7 = (((_5.0: std::ptr::Unique<std::vec::Vec<u32>>).0: std::ptr::NonNull<std::vec::Vec<u32>>).0: *const std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-- (*_7) = Vec::<u32>::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+ StorageLive(_8); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
-+ _8 = &mut (*_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
+ StorageLive(_5); // scope 0 at $DIR/inline_into_box_place.rs:+1:29: +1:43
+ _5 = ShallowInitBox(move _4, std::vec::Vec<u32>); // scope 0 at $DIR/inline_into_box_place.rs:+1:29: +1:43
+ _7 = (((_5.0: std::ptr::Unique<std::vec::Vec<u32>>).0: std::ptr::NonNull<std::vec::Vec<u32>>).0: *const std::vec::Vec<u32>); // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
+- (*_7) = Vec::<u32>::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
++ StorageLive(_8); // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
++ _8 = &mut (*_7); // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
+ StorageLive(_9); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+ _9 = const _; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
// mir::Constant
-- // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
+- // + span: $DIR/inline_into_box_place.rs:8:33: 8:41
- // + user_ty: UserType(1)
- // + literal: Const { ty: fn() -> Vec<u32> {Vec::<u32>::new}, val: Value(<ZST>) }
- }
+ ((*_8).0: alloc::raw_vec::RawVec<u32>) = move _9; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+ ((*_8).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+ StorageDead(_9); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
-+ StorageDead(_8); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43
- _1 = move _5; // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43
- StorageDead(_5); // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
- _0 = const (); // scope 0 at $DIR/inline-into-box-place.rs:+0:11: +2:2
-- drop(_1) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2
-+ drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2
++ StorageDead(_8); // scope 0 at $DIR/inline_into_box_place.rs:+1:33: +1:43
+ _1 = move _5; // scope 0 at $DIR/inline_into_box_place.rs:+1:29: +1:43
+ StorageDead(_5); // scope 0 at $DIR/inline_into_box_place.rs:+1:42: +1:43
+ _0 = const (); // scope 0 at $DIR/inline_into_box_place.rs:+0:11: +2:2
+- drop(_1) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline_into_box_place.rs:+2:1: +2:2
++ drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline_into_box_place.rs:+2:1: +2:2
}
- bb3: {
+ bb2: {
- StorageDead(_1); // scope 0 at $DIR/inline-into-box-place.rs:+2:1: +2:2
- return; // scope 0 at $DIR/inline-into-box-place.rs:+2:2: +2:2
+ StorageDead(_1); // scope 0 at $DIR/inline_into_box_place.rs:+2:1: +2:2
+ return; // scope 0 at $DIR/inline_into_box_place.rs:+2:2: +2:2
}
- bb4 (cleanup): {
+ bb3 (cleanup): {
- resume; // scope 0 at $DIR/inline-into-box-place.rs:+0:1: +2:2
+ resume; // scope 0 at $DIR/inline_into_box_place.rs:+0:1: +2:2
- }
-
- bb5 (cleanup): {
-- _6 = alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>(move (_5.0: std::ptr::Unique<std::vec::Vec<u32>>), move (_5.1: std::alloc::Global)) -> bb4; // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43
+- _6 = alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>(move (_5.0: std::ptr::Unique<std::vec::Vec<u32>>), move (_5.1: std::alloc::Global)) -> bb4; // scope 0 at $DIR/inline_into_box_place.rs:+1:42: +1:43
- // mir::Constant
-- // + span: $DIR/inline-into-box-place.rs:8:42: 8:43
+- // + span: $DIR/inline_into_box_place.rs:8:42: 8:43
- // + literal: Const { ty: unsafe fn(Unique<Vec<u32>>, std::alloc::Global) {alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>}, val: Value(<ZST>) }
}
}
--- /dev/null
+// ignore-endian-big
+// ignore-wasm32-bare compiled with panic=abort by default
+// compile-flags: -Z mir-opt-level=4
+
+#![feature(box_syntax)]
+// EMIT_MIR inline_into_box_place.main.Inline.diff
+fn main() {
+ let _x: Box<Vec<u32>> = box Vec::new();
+}
// MIR for `main` after Inline
fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/inline-options.rs:+0:11: +0:11
- let _1: (); // in scope 0 at $DIR/inline-options.rs:+1:5: +1:18
- let _2: (); // in scope 0 at $DIR/inline-options.rs:+2:5: +2:21
- scope 1 (inlined inlined::<u32>) { // at $DIR/inline-options.rs:10:5: 10:21
- let _3: (); // in scope 1 at $DIR/inline-options.rs:16:23: 16:26
- let _4: (); // in scope 1 at $DIR/inline-options.rs:16:28: 16:31
- let _5: (); // in scope 1 at $DIR/inline-options.rs:16:33: 16:36
+ let mut _0: (); // return place in scope 0 at $DIR/inline_options.rs:+0:11: +0:11
+ let _1: (); // in scope 0 at $DIR/inline_options.rs:+1:5: +1:18
+ let _2: (); // in scope 0 at $DIR/inline_options.rs:+2:5: +2:21
+ scope 1 (inlined inlined::<u32>) { // at $DIR/inline_options.rs:10:5: 10:21
+ let _3: (); // in scope 1 at $DIR/inline_options.rs:16:23: 16:26
+ let _4: (); // in scope 1 at $DIR/inline_options.rs:16:28: 16:31
+ let _5: (); // in scope 1 at $DIR/inline_options.rs:16:33: 16:36
}
bb0: {
- StorageLive(_1); // scope 0 at $DIR/inline-options.rs:+1:5: +1:18
- _1 = not_inlined() -> bb1; // scope 0 at $DIR/inline-options.rs:+1:5: +1:18
+ StorageLive(_1); // scope 0 at $DIR/inline_options.rs:+1:5: +1:18
+ _1 = not_inlined() -> bb1; // scope 0 at $DIR/inline_options.rs:+1:5: +1:18
// mir::Constant
- // + span: $DIR/inline-options.rs:9:5: 9:16
+ // + span: $DIR/inline_options.rs:9:5: 9:16
// + literal: Const { ty: fn() {not_inlined}, val: Value(<ZST>) }
}
bb1: {
- StorageDead(_1); // scope 0 at $DIR/inline-options.rs:+1:18: +1:19
- StorageLive(_2); // scope 0 at $DIR/inline-options.rs:+2:5: +2:21
- StorageLive(_3); // scope 1 at $DIR/inline-options.rs:16:23: 16:26
- _3 = g() -> bb2; // scope 1 at $DIR/inline-options.rs:16:23: 16:26
+ StorageDead(_1); // scope 0 at $DIR/inline_options.rs:+1:18: +1:19
+ StorageLive(_2); // scope 0 at $DIR/inline_options.rs:+2:5: +2:21
+ StorageLive(_3); // scope 1 at $DIR/inline_options.rs:16:23: 16:26
+ _3 = g() -> bb2; // scope 1 at $DIR/inline_options.rs:16:23: 16:26
// mir::Constant
- // + span: $DIR/inline-options.rs:16:23: 16:24
+ // + span: $DIR/inline_options.rs:16:23: 16:24
// + literal: Const { ty: fn() {g}, val: Value(<ZST>) }
}
bb2: {
- StorageDead(_3); // scope 1 at $DIR/inline-options.rs:16:26: 16:27
- StorageLive(_4); // scope 1 at $DIR/inline-options.rs:16:28: 16:31
- _4 = g() -> bb3; // scope 1 at $DIR/inline-options.rs:16:28: 16:31
+ StorageDead(_3); // scope 1 at $DIR/inline_options.rs:16:26: 16:27
+ StorageLive(_4); // scope 1 at $DIR/inline_options.rs:16:28: 16:31
+ _4 = g() -> bb3; // scope 1 at $DIR/inline_options.rs:16:28: 16:31
// mir::Constant
- // + span: $DIR/inline-options.rs:16:28: 16:29
+ // + span: $DIR/inline_options.rs:16:28: 16:29
// + literal: Const { ty: fn() {g}, val: Value(<ZST>) }
}
bb3: {
- StorageDead(_4); // scope 1 at $DIR/inline-options.rs:16:31: 16:32
- StorageLive(_5); // scope 1 at $DIR/inline-options.rs:16:33: 16:36
- _5 = g() -> bb4; // scope 1 at $DIR/inline-options.rs:16:33: 16:36
+ StorageDead(_4); // scope 1 at $DIR/inline_options.rs:16:31: 16:32
+ StorageLive(_5); // scope 1 at $DIR/inline_options.rs:16:33: 16:36
+ _5 = g() -> bb4; // scope 1 at $DIR/inline_options.rs:16:33: 16:36
// mir::Constant
- // + span: $DIR/inline-options.rs:16:33: 16:34
+ // + span: $DIR/inline_options.rs:16:33: 16:34
// + literal: Const { ty: fn() {g}, val: Value(<ZST>) }
}
bb4: {
- StorageDead(_5); // scope 1 at $DIR/inline-options.rs:16:36: 16:37
- StorageDead(_2); // scope 0 at $DIR/inline-options.rs:+2:21: +2:22
- _0 = const (); // scope 0 at $DIR/inline-options.rs:+0:11: +3:2
- return; // scope 0 at $DIR/inline-options.rs:+3:2: +3:2
+ StorageDead(_5); // scope 1 at $DIR/inline_options.rs:16:36: 16:37
+ StorageDead(_2); // scope 0 at $DIR/inline_options.rs:+2:21: +2:22
+ _0 = const (); // scope 0 at $DIR/inline_options.rs:+0:11: +3:2
+ return; // scope 0 at $DIR/inline_options.rs:+3:2: +3:2
}
}
--- /dev/null
+// Checks that inlining threshold can be controlled with
+// inline-mir-threshold and inline-hint-threshold options.
+//
+// compile-flags: -Zinline-mir-threshold=90
+// compile-flags: -Zinline-mir-hint-threshold=50
+
+// EMIT_MIR inline_options.main.Inline.after.mir
+fn main() {
+ not_inlined();
+ inlined::<u32>();
+}
+
+// Cost is approximately 3 * 25 + 5 = 80.
+#[inline]
+pub fn not_inlined() { g(); g(); g(); }
+pub fn inlined<T>() { g(); g(); g(); }
+
+#[inline(never)]
+fn g() {}
// MIR for `bar` after Inline
fn bar() -> bool {
- let mut _0: bool; // return place in scope 0 at $DIR/inline-retag.rs:+0:13: +0:17
- let _1: for<'a, 'b> fn(&'a i32, &'b i32) -> bool {foo}; // in scope 0 at $DIR/inline-retag.rs:+1:9: +1:10
- let mut _2: for<'a, 'b> fn(&'a i32, &'b i32) -> bool {foo}; // in scope 0 at $DIR/inline-retag.rs:+2:5: +2:6
- let mut _3: &i32; // in scope 0 at $DIR/inline-retag.rs:+2:7: +2:9
- let _4: &i32; // in scope 0 at $DIR/inline-retag.rs:+2:7: +2:9
- let _5: i32; // in scope 0 at $DIR/inline-retag.rs:+2:8: +2:9
- let mut _6: &i32; // in scope 0 at $DIR/inline-retag.rs:+2:11: +2:14
- let _7: &i32; // in scope 0 at $DIR/inline-retag.rs:+2:11: +2:14
- let _8: i32; // in scope 0 at $DIR/inline-retag.rs:+2:12: +2:14
+ let mut _0: bool; // return place in scope 0 at $DIR/inline_retag.rs:+0:13: +0:17
+ let _1: for<'a, 'b> fn(&'a i32, &'b i32) -> bool {foo}; // in scope 0 at $DIR/inline_retag.rs:+1:9: +1:10
+ let mut _2: for<'a, 'b> fn(&'a i32, &'b i32) -> bool {foo}; // in scope 0 at $DIR/inline_retag.rs:+2:5: +2:6
+ let mut _3: &i32; // in scope 0 at $DIR/inline_retag.rs:+2:7: +2:9
+ let _4: &i32; // in scope 0 at $DIR/inline_retag.rs:+2:7: +2:9
+ let _5: i32; // in scope 0 at $DIR/inline_retag.rs:+2:8: +2:9
+ let mut _6: &i32; // in scope 0 at $DIR/inline_retag.rs:+2:11: +2:14
+ let _7: &i32; // in scope 0 at $DIR/inline_retag.rs:+2:11: +2:14
+ let _8: i32; // in scope 0 at $DIR/inline_retag.rs:+2:12: +2:14
scope 1 {
- debug f => _1; // in scope 1 at $DIR/inline-retag.rs:+1:9: +1:10
- let mut _9: &i32; // in scope 1 at $DIR/inline-retag.rs:+2:11: +2:14
- let mut _10: &i32; // in scope 1 at $DIR/inline-retag.rs:+2:7: +2:9
- scope 2 (inlined foo) { // at $DIR/inline-retag.rs:12:5: 12:15
- debug x => _3; // in scope 2 at $DIR/inline-retag.rs:16:8: 16:9
- debug y => _6; // in scope 2 at $DIR/inline-retag.rs:16:17: 16:18
- let mut _11: i32; // in scope 2 at $DIR/inline-retag.rs:17:5: 17:7
- let mut _12: i32; // in scope 2 at $DIR/inline-retag.rs:17:11: 17:13
+ debug f => _1; // in scope 1 at $DIR/inline_retag.rs:+1:9: +1:10
+ let mut _9: &i32; // in scope 1 at $DIR/inline_retag.rs:+2:11: +2:14
+ let mut _10: &i32; // in scope 1 at $DIR/inline_retag.rs:+2:7: +2:9
+ scope 2 (inlined foo) { // at $DIR/inline_retag.rs:12:5: 12:15
+ debug x => _3; // in scope 2 at $DIR/inline_retag.rs:16:8: 16:9
+ debug y => _6; // in scope 2 at $DIR/inline_retag.rs:16:17: 16:18
+ let mut _11: i32; // in scope 2 at $DIR/inline_retag.rs:17:5: 17:7
+ let mut _12: i32; // in scope 2 at $DIR/inline_retag.rs:17:11: 17:13
}
}
bb0: {
- StorageLive(_1); // scope 0 at $DIR/inline-retag.rs:+1:9: +1:10
- _1 = foo; // scope 0 at $DIR/inline-retag.rs:+1:13: +1:16
+ StorageLive(_1); // scope 0 at $DIR/inline_retag.rs:+1:9: +1:10
+ _1 = foo; // scope 0 at $DIR/inline_retag.rs:+1:13: +1:16
// mir::Constant
- // + span: $DIR/inline-retag.rs:11:13: 11:16
+ // + span: $DIR/inline_retag.rs:11:13: 11:16
// + literal: Const { ty: for<'a, 'b> fn(&'a i32, &'b i32) -> bool {foo}, val: Value(<ZST>) }
- StorageLive(_2); // scope 1 at $DIR/inline-retag.rs:+2:5: +2:6
- _2 = _1; // scope 1 at $DIR/inline-retag.rs:+2:5: +2:6
- StorageLive(_3); // scope 1 at $DIR/inline-retag.rs:+2:7: +2:9
- StorageLive(_4); // scope 1 at $DIR/inline-retag.rs:+2:7: +2:9
- _10 = const _; // scope 1 at $DIR/inline-retag.rs:+2:7: +2:9
+ StorageLive(_2); // scope 1 at $DIR/inline_retag.rs:+2:5: +2:6
+ _2 = _1; // scope 1 at $DIR/inline_retag.rs:+2:5: +2:6
+ StorageLive(_3); // scope 1 at $DIR/inline_retag.rs:+2:7: +2:9
+ StorageLive(_4); // scope 1 at $DIR/inline_retag.rs:+2:7: +2:9
+ _10 = const _; // scope 1 at $DIR/inline_retag.rs:+2:7: +2:9
// mir::Constant
- // + span: $DIR/inline-retag.rs:12:7: 12:9
+ // + span: $DIR/inline_retag.rs:12:7: 12:9
// + literal: Const { ty: &i32, val: Unevaluated(bar, [], Some(promoted[1])) }
- Retag(_10); // scope 1 at $DIR/inline-retag.rs:+2:7: +2:9
- _4 = &(*_10); // scope 1 at $DIR/inline-retag.rs:+2:7: +2:9
- Retag(_4); // scope 1 at $DIR/inline-retag.rs:+2:7: +2:9
- _3 = &(*_4); // scope 1 at $DIR/inline-retag.rs:+2:7: +2:9
- Retag(_3); // scope 1 at $DIR/inline-retag.rs:+2:7: +2:9
- StorageLive(_6); // scope 1 at $DIR/inline-retag.rs:+2:11: +2:14
- StorageLive(_7); // scope 1 at $DIR/inline-retag.rs:+2:11: +2:14
- _9 = const _; // scope 1 at $DIR/inline-retag.rs:+2:11: +2:14
+ Retag(_10); // scope 1 at $DIR/inline_retag.rs:+2:7: +2:9
+ _4 = &(*_10); // scope 1 at $DIR/inline_retag.rs:+2:7: +2:9
+ Retag(_4); // scope 1 at $DIR/inline_retag.rs:+2:7: +2:9
+ _3 = &(*_4); // scope 1 at $DIR/inline_retag.rs:+2:7: +2:9
+ Retag(_3); // scope 1 at $DIR/inline_retag.rs:+2:7: +2:9
+ StorageLive(_6); // scope 1 at $DIR/inline_retag.rs:+2:11: +2:14
+ StorageLive(_7); // scope 1 at $DIR/inline_retag.rs:+2:11: +2:14
+ _9 = const _; // scope 1 at $DIR/inline_retag.rs:+2:11: +2:14
// mir::Constant
- // + span: $DIR/inline-retag.rs:12:11: 12:14
+ // + span: $DIR/inline_retag.rs:12:11: 12:14
// + literal: Const { ty: &i32, val: Unevaluated(bar, [], Some(promoted[0])) }
- Retag(_9); // scope 1 at $DIR/inline-retag.rs:+2:11: +2:14
- _7 = &(*_9); // scope 1 at $DIR/inline-retag.rs:+2:11: +2:14
- Retag(_7); // scope 1 at $DIR/inline-retag.rs:+2:11: +2:14
- _6 = &(*_7); // scope 1 at $DIR/inline-retag.rs:+2:11: +2:14
- Retag(_6); // scope 1 at $DIR/inline-retag.rs:+2:11: +2:14
- Retag(_3); // scope 2 at $DIR/inline-retag.rs:16:8: 16:9
- Retag(_6); // scope 2 at $DIR/inline-retag.rs:16:17: 16:18
- StorageLive(_11); // scope 2 at $DIR/inline-retag.rs:17:5: 17:7
- _11 = (*_3); // scope 2 at $DIR/inline-retag.rs:17:5: 17:7
- StorageLive(_12); // scope 2 at $DIR/inline-retag.rs:17:11: 17:13
- _12 = (*_6); // scope 2 at $DIR/inline-retag.rs:17:11: 17:13
- _0 = Eq(move _11, move _12); // scope 2 at $DIR/inline-retag.rs:17:5: 17:13
- StorageDead(_12); // scope 2 at $DIR/inline-retag.rs:17:12: 17:13
- StorageDead(_11); // scope 2 at $DIR/inline-retag.rs:17:12: 17:13
- StorageDead(_6); // scope 1 at $DIR/inline-retag.rs:+2:14: +2:15
- StorageDead(_3); // scope 1 at $DIR/inline-retag.rs:+2:14: +2:15
- StorageDead(_2); // scope 1 at $DIR/inline-retag.rs:+2:14: +2:15
- StorageDead(_1); // scope 0 at $DIR/inline-retag.rs:+3:1: +3:2
- StorageDead(_7); // scope 0 at $DIR/inline-retag.rs:+3:1: +3:2
- StorageDead(_4); // scope 0 at $DIR/inline-retag.rs:+3:1: +3:2
- return; // scope 0 at $DIR/inline-retag.rs:+3:2: +3:2
+ Retag(_9); // scope 1 at $DIR/inline_retag.rs:+2:11: +2:14
+ _7 = &(*_9); // scope 1 at $DIR/inline_retag.rs:+2:11: +2:14
+ Retag(_7); // scope 1 at $DIR/inline_retag.rs:+2:11: +2:14
+ _6 = &(*_7); // scope 1 at $DIR/inline_retag.rs:+2:11: +2:14
+ Retag(_6); // scope 1 at $DIR/inline_retag.rs:+2:11: +2:14
+ Retag(_3); // scope 2 at $DIR/inline_retag.rs:16:8: 16:9
+ Retag(_6); // scope 2 at $DIR/inline_retag.rs:16:17: 16:18
+ StorageLive(_11); // scope 2 at $DIR/inline_retag.rs:17:5: 17:7
+ _11 = (*_3); // scope 2 at $DIR/inline_retag.rs:17:5: 17:7
+ StorageLive(_12); // scope 2 at $DIR/inline_retag.rs:17:11: 17:13
+ _12 = (*_6); // scope 2 at $DIR/inline_retag.rs:17:11: 17:13
+ _0 = Eq(move _11, move _12); // scope 2 at $DIR/inline_retag.rs:17:5: 17:13
+ StorageDead(_12); // scope 2 at $DIR/inline_retag.rs:17:12: 17:13
+ StorageDead(_11); // scope 2 at $DIR/inline_retag.rs:17:12: 17:13
+ StorageDead(_6); // scope 1 at $DIR/inline_retag.rs:+2:14: +2:15
+ StorageDead(_3); // scope 1 at $DIR/inline_retag.rs:+2:14: +2:15
+ StorageDead(_2); // scope 1 at $DIR/inline_retag.rs:+2:14: +2:15
+ StorageDead(_1); // scope 0 at $DIR/inline_retag.rs:+3:1: +3:2
+ StorageDead(_7); // scope 0 at $DIR/inline_retag.rs:+3:1: +3:2
+ StorageDead(_4); // scope 0 at $DIR/inline_retag.rs:+3:1: +3:2
+ return; // scope 0 at $DIR/inline_retag.rs:+3:2: +3:2
}
}
--- /dev/null
+// compile-flags: -Z span_free_formats -Z mir-emit-retag
+
+// Tests that MIR inliner fixes up `Retag`'s `fn_entry` flag
+
+fn main() {
+ println!("{}", bar());
+}
+
+// EMIT_MIR inline_retag.bar.Inline.after.mir
+fn bar() -> bool {
+ let f = foo;
+ f(&1, &-1)
+}
+
+#[inline(always)]
+fn foo(x: &i32, y: &i32) -> bool {
+ *x == *y
+}
+ // MIR for `clone` after Inline
fn clone(_1: fn(A, B)) -> fn(A, B) {
- debug f => _1; // in scope 0 at $DIR/inline-shims.rs:+0:20: +0:21
- let mut _0: fn(A, B); // return place in scope 0 at $DIR/inline-shims.rs:+0:36: +0:44
- let mut _2: &fn(A, B); // in scope 0 at $DIR/inline-shims.rs:+1:5: +1:14
-+ scope 1 (inlined <fn(A, B) as Clone>::clone - shim(fn(A, B))) { // at $DIR/inline-shims.rs:6:5: 6:14
+ debug f => _1; // in scope 0 at $DIR/inline_shims.rs:+0:20: +0:21
+ let mut _0: fn(A, B); // return place in scope 0 at $DIR/inline_shims.rs:+0:36: +0:44
+ let mut _2: &fn(A, B); // in scope 0 at $DIR/inline_shims.rs:+1:5: +1:14
++ scope 1 (inlined <fn(A, B) as Clone>::clone - shim(fn(A, B))) { // at $DIR/inline_shims.rs:6:5: 6:14
+ }
bb0: {
- StorageLive(_2); // scope 0 at $DIR/inline-shims.rs:+1:5: +1:14
- _2 = &_1; // scope 0 at $DIR/inline-shims.rs:+1:5: +1:14
-- _0 = <fn(A, B) as Clone>::clone(move _2) -> bb1; // scope 0 at $DIR/inline-shims.rs:+1:5: +1:14
+ StorageLive(_2); // scope 0 at $DIR/inline_shims.rs:+1:5: +1:14
+ _2 = &_1; // scope 0 at $DIR/inline_shims.rs:+1:5: +1:14
+- _0 = <fn(A, B) as Clone>::clone(move _2) -> bb1; // scope 0 at $DIR/inline_shims.rs:+1:5: +1:14
- // mir::Constant
-- // + span: $DIR/inline-shims.rs:6:7: 6:12
+- // + span: $DIR/inline_shims.rs:6:7: 6:12
- // + literal: Const { ty: for<'a> fn(&'a fn(A, B)) -> fn(A, B) {<fn(A, B) as Clone>::clone}, val: Value(<ZST>) }
- }
-
- bb1: {
+ _0 = (*_2); // scope 1 at $SRC_DIR/core/src/clone.rs:LL:COL
- StorageDead(_2); // scope 0 at $DIR/inline-shims.rs:+1:13: +1:14
- return; // scope 0 at $DIR/inline-shims.rs:+2:2: +2:2
+ StorageDead(_2); // scope 0 at $DIR/inline_shims.rs:+1:13: +1:14
+ return; // scope 0 at $DIR/inline_shims.rs:+2:2: +2:2
}
}
+ // MIR for `drop` after Inline
fn drop(_1: *mut Vec<A>, _2: *mut Option<B>) -> () {
- debug a => _1; // in scope 0 at $DIR/inline-shims.rs:+0:19: +0:20
- debug b => _2; // in scope 0 at $DIR/inline-shims.rs:+0:35: +0:36
- let mut _0: (); // return place in scope 0 at $DIR/inline-shims.rs:+0:54: +0:54
- let _3: (); // in scope 0 at $DIR/inline-shims.rs:+1:14: +1:40
- let mut _4: *mut std::vec::Vec<A>; // in scope 0 at $DIR/inline-shims.rs:+1:38: +1:39
- let mut _5: *mut std::option::Option<B>; // in scope 0 at $DIR/inline-shims.rs:+2:38: +2:39
+ debug a => _1; // in scope 0 at $DIR/inline_shims.rs:+0:19: +0:20
+ debug b => _2; // in scope 0 at $DIR/inline_shims.rs:+0:35: +0:36
+ let mut _0: (); // return place in scope 0 at $DIR/inline_shims.rs:+0:54: +0:54
+ let _3: (); // in scope 0 at $DIR/inline_shims.rs:+1:14: +1:40
+ let mut _4: *mut std::vec::Vec<A>; // in scope 0 at $DIR/inline_shims.rs:+1:38: +1:39
+ let mut _5: *mut std::option::Option<B>; // in scope 0 at $DIR/inline_shims.rs:+2:38: +2:39
scope 1 {
}
scope 2 {
-+ scope 3 (inlined std::ptr::drop_in_place::<Option<B>> - shim(Some(Option<B>))) { // at $DIR/inline-shims.rs:12:14: 12:40
++ scope 3 (inlined std::ptr::drop_in_place::<Option<B>> - shim(Some(Option<B>))) { // at $DIR/inline_shims.rs:12:14: 12:40
+ let mut _6: isize; // in scope 3 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+ let mut _7: isize; // in scope 3 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+ }
}
bb0: {
- StorageLive(_3); // scope 0 at $DIR/inline-shims.rs:+1:5: +1:42
- StorageLive(_4); // scope 1 at $DIR/inline-shims.rs:+1:38: +1:39
- _4 = _1; // scope 1 at $DIR/inline-shims.rs:+1:38: +1:39
- _3 = std::ptr::drop_in_place::<Vec<A>>(move _4) -> bb1; // scope 1 at $DIR/inline-shims.rs:+1:14: +1:40
+ StorageLive(_3); // scope 0 at $DIR/inline_shims.rs:+1:5: +1:42
+ StorageLive(_4); // scope 1 at $DIR/inline_shims.rs:+1:38: +1:39
+ _4 = _1; // scope 1 at $DIR/inline_shims.rs:+1:38: +1:39
+ _3 = std::ptr::drop_in_place::<Vec<A>>(move _4) -> bb1; // scope 1 at $DIR/inline_shims.rs:+1:14: +1:40
// mir::Constant
- // + span: $DIR/inline-shims.rs:11:14: 11:37
+ // + span: $DIR/inline_shims.rs:11:14: 11:37
// + literal: Const { ty: unsafe fn(*mut Vec<A>) {std::ptr::drop_in_place::<Vec<A>>}, val: Value(<ZST>) }
}
bb1: {
- StorageDead(_4); // scope 1 at $DIR/inline-shims.rs:+1:39: +1:40
- StorageDead(_3); // scope 0 at $DIR/inline-shims.rs:+1:41: +1:42
- StorageLive(_5); // scope 2 at $DIR/inline-shims.rs:+2:38: +2:39
- _5 = _2; // scope 2 at $DIR/inline-shims.rs:+2:38: +2:39
-- _0 = std::ptr::drop_in_place::<Option<B>>(move _5) -> bb2; // scope 2 at $DIR/inline-shims.rs:+2:14: +2:40
+ StorageDead(_4); // scope 1 at $DIR/inline_shims.rs:+1:39: +1:40
+ StorageDead(_3); // scope 0 at $DIR/inline_shims.rs:+1:41: +1:42
+ StorageLive(_5); // scope 2 at $DIR/inline_shims.rs:+2:38: +2:39
+ _5 = _2; // scope 2 at $DIR/inline_shims.rs:+2:38: +2:39
+- _0 = std::ptr::drop_in_place::<Option<B>>(move _5) -> bb2; // scope 2 at $DIR/inline_shims.rs:+2:14: +2:40
- // mir::Constant
-- // + span: $DIR/inline-shims.rs:12:14: 12:37
+- // + span: $DIR/inline_shims.rs:12:14: 12:37
- // + literal: Const { ty: unsafe fn(*mut Option<B>) {std::ptr::drop_in_place::<Option<B>>}, val: Value(<ZST>) }
-+ StorageLive(_6); // scope 2 at $DIR/inline-shims.rs:+2:14: +2:40
-+ StorageLive(_7); // scope 2 at $DIR/inline-shims.rs:+2:14: +2:40
++ StorageLive(_6); // scope 2 at $DIR/inline_shims.rs:+2:14: +2:40
++ StorageLive(_7); // scope 2 at $DIR/inline_shims.rs:+2:14: +2:40
+ _6 = discriminant((*_5)); // scope 3 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
+ switchInt(move _6) -> [0_isize: bb2, otherwise: bb3]; // scope 3 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
}
bb2: {
-+ StorageDead(_7); // scope 2 at $DIR/inline-shims.rs:+2:14: +2:40
-+ StorageDead(_6); // scope 2 at $DIR/inline-shims.rs:+2:14: +2:40
- StorageDead(_5); // scope 2 at $DIR/inline-shims.rs:+2:39: +2:40
- return; // scope 0 at $DIR/inline-shims.rs:+3:2: +3:2
++ StorageDead(_7); // scope 2 at $DIR/inline_shims.rs:+2:14: +2:40
++ StorageDead(_6); // scope 2 at $DIR/inline_shims.rs:+2:14: +2:40
+ StorageDead(_5); // scope 2 at $DIR/inline_shims.rs:+2:39: +2:40
+ return; // scope 0 at $DIR/inline_shims.rs:+3:2: +3:2
+ }
+
+ bb3: {
--- /dev/null
+// ignore-wasm32-bare compiled with panic=abort by default
+#![crate_type = "lib"]
+
+// EMIT_MIR inline_shims.clone.Inline.diff
+pub fn clone<A, B>(f: fn(A, B)) -> fn(A, B) {
+ f.clone()
+}
+
+// EMIT_MIR inline_shims.drop.Inline.diff
+pub fn drop<A, B>(a: *mut Vec<A>, b: *mut Option<B>) {
+ unsafe { std::ptr::drop_in_place(a) }
+ unsafe { std::ptr::drop_in_place(b) }
+}
+ // MIR for `main` after Inline
fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/inline-specialization.rs:+0:11: +0:11
- let _1: u32; // in scope 0 at $DIR/inline-specialization.rs:+1:9: +1:10
+ let mut _0: (); // return place in scope 0 at $DIR/inline_specialization.rs:+0:11: +0:11
+ let _1: u32; // in scope 0 at $DIR/inline_specialization.rs:+1:9: +1:10
scope 1 {
- debug x => _1; // in scope 1 at $DIR/inline-specialization.rs:+1:9: +1:10
+ debug x => _1; // in scope 1 at $DIR/inline_specialization.rs:+1:9: +1:10
}
-+ scope 2 (inlined <Vec<()> as Foo>::bar) { // at $DIR/inline-specialization.rs:5:13: 5:38
++ scope 2 (inlined <Vec<()> as Foo>::bar) { // at $DIR/inline_specialization.rs:5:13: 5:38
+ }
bb0: {
- StorageLive(_1); // scope 0 at $DIR/inline-specialization.rs:+1:9: +1:10
-- _1 = <Vec<()> as Foo>::bar() -> bb1; // scope 0 at $DIR/inline-specialization.rs:+1:13: +1:38
+ StorageLive(_1); // scope 0 at $DIR/inline_specialization.rs:+1:9: +1:10
+- _1 = <Vec<()> as Foo>::bar() -> bb1; // scope 0 at $DIR/inline_specialization.rs:+1:13: +1:38
- // mir::Constant
-- // + span: $DIR/inline-specialization.rs:5:13: 5:36
+- // + span: $DIR/inline_specialization.rs:5:13: 5:36
- // + literal: Const { ty: fn() -> u32 {<Vec<()> as Foo>::bar}, val: Value(<ZST>) }
- }
-
- bb1: {
-+ _1 = const 123_u32; // scope 2 at $DIR/inline-specialization.rs:14:31: 14:34
- _0 = const (); // scope 0 at $DIR/inline-specialization.rs:+0:11: +2:2
- StorageDead(_1); // scope 0 at $DIR/inline-specialization.rs:+2:1: +2:2
- return; // scope 0 at $DIR/inline-specialization.rs:+2:2: +2:2
++ _1 = const 123_u32; // scope 2 at $DIR/inline_specialization.rs:14:31: 14:34
+ _0 = const (); // scope 0 at $DIR/inline_specialization.rs:+0:11: +2:2
+ StorageDead(_1); // scope 0 at $DIR/inline_specialization.rs:+2:1: +2:2
+ return; // scope 0 at $DIR/inline_specialization.rs:+2:2: +2:2
}
}
--- /dev/null
+#![feature(specialization)]
+
+// EMIT_MIR inline_specialization.main.Inline.diff
+fn main() {
+ let x = <Vec::<()> as Foo>::bar();
+}
+
+trait Foo {
+ fn bar() -> u32;
+}
+
+impl<T> Foo for Vec<T> {
+ #[inline(always)]
+ default fn bar() -> u32 { 123 }
+}
--- /dev/null
+// compile-flags: -Z span_free_formats
+
+fn main() {
+ println!("{}", test(&()));
+}
+
+// EMIT_MIR inline_trait_method.test.Inline.after.mir
+fn test(x: &dyn X) -> u32 {
+ x.y()
+}
+
+trait X {
+ fn y(&self) -> u32 {
+ 1
+ }
+}
+
+impl X for () {
+ fn y(&self) -> u32 {
+ 2
+ }
+}
// MIR for `test` after Inline
fn test(_1: &dyn X) -> u32 {
- debug x => _1; // in scope 0 at $DIR/inline-trait-method.rs:+0:9: +0:10
- let mut _0: u32; // return place in scope 0 at $DIR/inline-trait-method.rs:+0:23: +0:26
- let mut _2: &dyn X; // in scope 0 at $DIR/inline-trait-method.rs:+1:5: +1:10
+ debug x => _1; // in scope 0 at $DIR/inline_trait_method.rs:+0:9: +0:10
+ let mut _0: u32; // return place in scope 0 at $DIR/inline_trait_method.rs:+0:23: +0:26
+ let mut _2: &dyn X; // in scope 0 at $DIR/inline_trait_method.rs:+1:5: +1:10
bb0: {
- StorageLive(_2); // scope 0 at $DIR/inline-trait-method.rs:+1:5: +1:10
- _2 = &(*_1); // scope 0 at $DIR/inline-trait-method.rs:+1:5: +1:10
- _0 = <dyn X as X>::y(move _2) -> bb1; // scope 0 at $DIR/inline-trait-method.rs:+1:5: +1:10
+ StorageLive(_2); // scope 0 at $DIR/inline_trait_method.rs:+1:5: +1:10
+ _2 = &(*_1); // scope 0 at $DIR/inline_trait_method.rs:+1:5: +1:10
+ _0 = <dyn X as X>::y(move _2) -> bb1; // scope 0 at $DIR/inline_trait_method.rs:+1:5: +1:10
// mir::Constant
- // + span: $DIR/inline-trait-method.rs:9:7: 9:8
+ // + span: $DIR/inline_trait_method.rs:9:7: 9:8
// + literal: Const { ty: for<'a> fn(&'a dyn X) -> u32 {<dyn X as X>::y}, val: Value(<ZST>) }
}
bb1: {
- StorageDead(_2); // scope 0 at $DIR/inline-trait-method.rs:+1:9: +1:10
- return; // scope 0 at $DIR/inline-trait-method.rs:+2:2: +2:2
+ StorageDead(_2); // scope 0 at $DIR/inline_trait_method.rs:+1:9: +1:10
+ return; // scope 0 at $DIR/inline_trait_method.rs:+2:2: +2:2
}
}
--- /dev/null
+// compile-flags: -Z span_free_formats -Z mir-opt-level=4
+
+// EMIT_MIR inline_trait_method_2.test2.Inline.after.mir
+fn test2(x: &dyn X) -> bool {
+ test(x)
+}
+
+#[inline]
+fn test(x: &dyn X) -> bool {
+ x.y()
+}
+
+trait X {
+ fn y(&self) -> bool {
+ false
+ }
+}
+
+impl X for () {
+ fn y(&self) -> bool {
+ true
+ }
+}
+
+fn main() {
+ println!("Should be true: {}", test2(&()));
+}
// MIR for `test2` after Inline
fn test2(_1: &dyn X) -> bool {
- debug x => _1; // in scope 0 at $DIR/inline-trait-method_2.rs:+0:10: +0:11
- let mut _0: bool; // return place in scope 0 at $DIR/inline-trait-method_2.rs:+0:24: +0:28
- let mut _2: &dyn X; // in scope 0 at $DIR/inline-trait-method_2.rs:+1:10: +1:11
- let mut _3: &dyn X; // in scope 0 at $DIR/inline-trait-method_2.rs:+1:10: +1:11
- scope 1 (inlined test) { // at $DIR/inline-trait-method_2.rs:5:5: 5:12
- debug x => _2; // in scope 1 at $DIR/inline-trait-method_2.rs:9:9: 9:10
- let mut _4: &dyn X; // in scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:10
+ debug x => _1; // in scope 0 at $DIR/inline_trait_method_2.rs:+0:10: +0:11
+ let mut _0: bool; // return place in scope 0 at $DIR/inline_trait_method_2.rs:+0:24: +0:28
+ let mut _2: &dyn X; // in scope 0 at $DIR/inline_trait_method_2.rs:+1:10: +1:11
+ let mut _3: &dyn X; // in scope 0 at $DIR/inline_trait_method_2.rs:+1:10: +1:11
+ scope 1 (inlined test) { // at $DIR/inline_trait_method_2.rs:5:5: 5:12
+ debug x => _2; // in scope 1 at $DIR/inline_trait_method_2.rs:9:9: 9:10
+ let mut _4: &dyn X; // in scope 1 at $DIR/inline_trait_method_2.rs:10:5: 10:10
}
bb0: {
- StorageLive(_2); // scope 0 at $DIR/inline-trait-method_2.rs:+1:10: +1:11
- StorageLive(_3); // scope 0 at $DIR/inline-trait-method_2.rs:+1:10: +1:11
- _3 = &(*_1); // scope 0 at $DIR/inline-trait-method_2.rs:+1:10: +1:11
- _2 = move _3 as &dyn X (Pointer(Unsize)); // scope 0 at $DIR/inline-trait-method_2.rs:+1:10: +1:11
- StorageDead(_3); // scope 0 at $DIR/inline-trait-method_2.rs:+1:10: +1:11
- StorageLive(_4); // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:10
- _4 = _2; // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:10
- _0 = <dyn X as X>::y(move _4) -> bb1; // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:10
+ StorageLive(_2); // scope 0 at $DIR/inline_trait_method_2.rs:+1:10: +1:11
+ StorageLive(_3); // scope 0 at $DIR/inline_trait_method_2.rs:+1:10: +1:11
+ _3 = &(*_1); // scope 0 at $DIR/inline_trait_method_2.rs:+1:10: +1:11
+ _2 = move _3 as &dyn X (Pointer(Unsize)); // scope 0 at $DIR/inline_trait_method_2.rs:+1:10: +1:11
+ StorageDead(_3); // scope 0 at $DIR/inline_trait_method_2.rs:+1:10: +1:11
+ StorageLive(_4); // scope 1 at $DIR/inline_trait_method_2.rs:10:5: 10:10
+ _4 = _2; // scope 1 at $DIR/inline_trait_method_2.rs:10:5: 10:10
+ _0 = <dyn X as X>::y(move _4) -> bb1; // scope 1 at $DIR/inline_trait_method_2.rs:10:5: 10:10
// mir::Constant
- // + span: $DIR/inline-trait-method_2.rs:10:7: 10:8
+ // + span: $DIR/inline_trait_method_2.rs:10:7: 10:8
// + literal: Const { ty: for<'a> fn(&'a dyn X) -> bool {<dyn X as X>::y}, val: Value(<ZST>) }
}
bb1: {
- StorageDead(_4); // scope 1 at $DIR/inline-trait-method_2.rs:10:9: 10:10
- StorageDead(_2); // scope 0 at $DIR/inline-trait-method_2.rs:+1:11: +1:12
- return; // scope 0 at $DIR/inline-trait-method_2.rs:+2:2: +2:2
+ StorageDead(_4); // scope 1 at $DIR/inline_trait_method_2.rs:10:9: 10:10
+ StorageDead(_2); // scope 0 at $DIR/inline_trait_method_2.rs:+1:11: +1:12
+ return; // scope 0 at $DIR/inline_trait_method_2.rs:+2:2: +2:2
}
}
+++ /dev/null
-// EMIT_MIR issue_58867_inline_as_ref_as_mut.a.Inline.after.mir
-pub fn a<T>(x: &mut [T]) -> &mut [T] {
- x.as_mut()
-}
-
-// EMIT_MIR issue_58867_inline_as_ref_as_mut.b.Inline.after.mir
-pub fn b<T>(x: &mut Box<T>) -> &mut T {
- x.as_mut()
-}
-
-// EMIT_MIR issue_58867_inline_as_ref_as_mut.c.Inline.after.mir
-pub fn c<T>(x: &[T]) -> &[T] {
- x.as_ref()
-}
-
-// EMIT_MIR issue_58867_inline_as_ref_as_mut.d.Inline.after.mir
-pub fn d<T>(x: &Box<T>) -> &T {
- x.as_ref()
-}
-
-fn main() {
- let mut boxed = Box::new(1);
- println!("{:?}", a(&mut [1]));
- println!("{:?}", b(&mut boxed));
- println!("{:?}", c(&[1]));
- println!("{:?}", d(&boxed));
-}
+++ /dev/null
-// Tests that MIR inliner can handle `SourceScopeData` parenting correctly. (#76997)
-
-// EMIT_MIR issue_76997_inline_scopes_parenting.main.Inline.after.mir
-fn main() {
- let f = |x| { let y = x; y };
- f(())
-}
+++ /dev/null
-// compile-flags: -Z mir-opt-level=3 -Z inline-mir
-// ignore-wasm32-bare compiled with panic=abort by default
-#![crate_type = "lib"]
-
-// EMIT_MIR issue_78442.bar.RevealAll.diff
-// EMIT_MIR issue_78442.bar.Inline.diff
-pub fn bar<P>(
- // Error won't happen if "bar" is not generic
- _baz: P,
-) {
- hide_foo()();
-}
-
-fn hide_foo() -> impl Fn() {
- // Error won't happen if "iterate" hasn't impl Trait or has generics
- foo
-}
-
-fn foo() { // Error won't happen if "foo" isn't used in "iterate" or has generics
-}
// MIR for `a` after Inline
fn a(_1: &mut [T]) -> &mut [T] {
- debug x => _1; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:13: +0:14
- let mut _0: &mut [T]; // return place in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:29: +0:37
- let mut _2: &mut [T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
- let mut _3: &mut [T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
- let mut _4: &mut [T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
- scope 1 (inlined <[T] as AsMut<[T]>>::as_mut) { // at $DIR/issue-58867-inline-as-ref-as-mut.rs:3:5: 3:15
+ debug x => _1; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+0:13: +0:14
+ let mut _0: &mut [T]; // return place in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+0:29: +0:37
+ let mut _2: &mut [T]; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
+ let mut _3: &mut [T]; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
+ let mut _4: &mut [T]; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
+ scope 1 (inlined <[T] as AsMut<[T]>>::as_mut) { // at $DIR/issue_58867_inline_as_ref_as_mut.rs:3:5: 3:15
debug self => _4; // in scope 1 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
let mut _5: &mut [T]; // in scope 1 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
}
bb0: {
- StorageLive(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
- StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
- StorageLive(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
- _4 = &mut (*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
+ StorageLive(_2); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
+ StorageLive(_3); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
+ StorageLive(_4); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
+ _4 = &mut (*_1); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
StorageLive(_5); // scope 1 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
_5 = &mut (*_4); // scope 1 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
_3 = &mut (*_5); // scope 1 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
StorageDead(_5); // scope 1 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
- _2 = &mut (*_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
- StorageDead(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:14: +1:15
- _0 = &mut (*_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
- StorageDead(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:1: +2:2
- StorageDead(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:1: +2:2
- return; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:2: +2:2
+ _2 = &mut (*_3); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
+ StorageDead(_4); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:14: +1:15
+ _0 = &mut (*_2); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
+ StorageDead(_3); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+2:1: +2:2
+ StorageDead(_2); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+2:1: +2:2
+ return; // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+2:2: +2:2
}
}
// MIR for `b` after Inline
fn b(_1: &mut Box<T>) -> &mut T {
- debug x => _1; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:13: +0:14
- let mut _0: &mut T; // return place in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:32: +0:38
- let mut _2: &mut T; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
- let mut _3: &mut T; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
- let mut _4: &mut std::boxed::Box<T>; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
- scope 1 (inlined <Box<T> as AsMut<T>>::as_mut) { // at $DIR/issue-58867-inline-as-ref-as-mut.rs:8:5: 8:15
+ debug x => _1; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+0:13: +0:14
+ let mut _0: &mut T; // return place in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+0:32: +0:38
+ let mut _2: &mut T; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
+ let mut _3: &mut T; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
+ let mut _4: &mut std::boxed::Box<T>; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
+ scope 1 (inlined <Box<T> as AsMut<T>>::as_mut) { // at $DIR/issue_58867_inline_as_ref_as_mut.rs:8:5: 8:15
debug self => _4; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
let mut _5: &mut T; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
let mut _6: &mut T; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
}
bb0: {
- StorageLive(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
- StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
- StorageLive(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
- _4 = &mut (*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
+ StorageLive(_2); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
+ StorageLive(_3); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
+ StorageLive(_4); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
+ _4 = &mut (*_1); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
StorageLive(_5); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
StorageLive(_6); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
_7 = deref_copy (*_4); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
_3 = &mut (*_5); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
StorageDead(_6); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
StorageDead(_5); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
- _2 = &mut (*_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
- StorageDead(_4); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:14: +1:15
- _0 = &mut (*_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
- StorageDead(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:1: +2:2
- StorageDead(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:1: +2:2
- return; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:2: +2:2
+ _2 = &mut (*_3); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
+ StorageDead(_4); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:14: +1:15
+ _0 = &mut (*_2); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
+ StorageDead(_3); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+2:1: +2:2
+ StorageDead(_2); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+2:1: +2:2
+ return; // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+2:2: +2:2
}
}
// MIR for `c` after Inline
fn c(_1: &[T]) -> &[T] {
- debug x => _1; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:13: +0:14
- let mut _0: &[T]; // return place in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:25: +0:29
- let _2: &[T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
- let mut _3: &[T]; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
- scope 1 (inlined <[T] as AsRef<[T]>>::as_ref) { // at $DIR/issue-58867-inline-as-ref-as-mut.rs:13:5: 13:15
+ debug x => _1; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+0:13: +0:14
+ let mut _0: &[T]; // return place in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+0:25: +0:29
+ let _2: &[T]; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
+ let mut _3: &[T]; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
+ scope 1 (inlined <[T] as AsRef<[T]>>::as_ref) { // at $DIR/issue_58867_inline_as_ref_as_mut.rs:13:5: 13:15
debug self => _3; // in scope 1 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
}
bb0: {
- StorageLive(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
- StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
- _3 = &(*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
+ StorageLive(_2); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
+ StorageLive(_3); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
+ _3 = &(*_1); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
_2 = _3; // scope 1 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
- _0 = &(*_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
- StorageDead(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:14: +1:15
- StorageDead(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:1: +2:2
- return; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:2: +2:2
+ _0 = &(*_2); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
+ StorageDead(_3); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:14: +1:15
+ StorageDead(_2); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+2:1: +2:2
+ return; // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+2:2: +2:2
}
}
// MIR for `d` after Inline
fn d(_1: &Box<T>) -> &T {
- debug x => _1; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:13: +0:14
- let mut _0: &T; // return place in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+0:28: +0:30
- let _2: &T; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
- let mut _3: &std::boxed::Box<T>; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
- scope 1 (inlined <Box<T> as AsRef<T>>::as_ref) { // at $DIR/issue-58867-inline-as-ref-as-mut.rs:18:5: 18:15
+ debug x => _1; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+0:13: +0:14
+ let mut _0: &T; // return place in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+0:28: +0:30
+ let _2: &T; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
+ let mut _3: &std::boxed::Box<T>; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
+ scope 1 (inlined <Box<T> as AsRef<T>>::as_ref) { // at $DIR/issue_58867_inline_as_ref_as_mut.rs:18:5: 18:15
debug self => _3; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
let mut _4: std::boxed::Box<T>; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
let mut _5: *const T; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
}
bb0: {
- StorageLive(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
- StorageLive(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
- _3 = &(*_1); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
+ StorageLive(_2); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
+ StorageLive(_3); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
+ _3 = &(*_1); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
_4 = deref_copy (*_3); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
_5 = (((_4.0: std::ptr::Unique<T>).0: std::ptr::NonNull<T>).0: *const T); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
_2 = &(*_5); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL
- _0 = &(*_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:5: +1:15
- StorageDead(_3); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+1:14: +1:15
- StorageDead(_2); // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:1: +2:2
- return; // scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:+2:2: +2:2
+ _0 = &(*_2); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15
+ StorageDead(_3); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:14: +1:15
+ StorageDead(_2); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+2:1: +2:2
+ return; // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+2:2: +2:2
}
}
--- /dev/null
+// EMIT_MIR issue_58867_inline_as_ref_as_mut.a.Inline.after.mir
+pub fn a<T>(x: &mut [T]) -> &mut [T] {
+ x.as_mut()
+}
+
+// EMIT_MIR issue_58867_inline_as_ref_as_mut.b.Inline.after.mir
+pub fn b<T>(x: &mut Box<T>) -> &mut T {
+ x.as_mut()
+}
+
+// EMIT_MIR issue_58867_inline_as_ref_as_mut.c.Inline.after.mir
+pub fn c<T>(x: &[T]) -> &[T] {
+ x.as_ref()
+}
+
+// EMIT_MIR issue_58867_inline_as_ref_as_mut.d.Inline.after.mir
+pub fn d<T>(x: &Box<T>) -> &T {
+ x.as_ref()
+}
+
+fn main() {
+ let mut boxed = Box::new(1);
+ println!("{:?}", a(&mut [1]));
+ println!("{:?}", b(&mut boxed));
+ println!("{:?}", c(&[1]));
+ println!("{:?}", d(&boxed));
+}
// MIR for `main` after Inline
fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+0:11: +0:11
- let _1: [closure@$DIR/issue-76997-inline-scopes-parenting.rs:5:13: 5:16]; // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+1:9: +1:10
- let mut _2: &[closure@$DIR/issue-76997-inline-scopes-parenting.rs:5:13: 5:16]; // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:5: +2:6
- let mut _3: ((),); // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:5: +2:10
- let mut _4: (); // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:7: +2:9
- let mut _5: (); // in scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:5: +2:10
+ let mut _0: (); // return place in scope 0 at $DIR/issue_76997_inline_scopes_parenting.rs:+0:11: +0:11
+ let _1: [closure@$DIR/issue_76997_inline_scopes_parenting.rs:5:13: 5:16]; // in scope 0 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:9: +1:10
+ let mut _2: &[closure@$DIR/issue_76997_inline_scopes_parenting.rs:5:13: 5:16]; // in scope 0 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:6
+ let mut _3: ((),); // in scope 0 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:10
+ let mut _4: (); // in scope 0 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:7: +2:9
+ let mut _5: (); // in scope 0 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:10
scope 1 {
- debug f => _1; // in scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+1:9: +1:10
- scope 2 (inlined main::{closure#0}) { // at $DIR/issue-76997-inline-scopes-parenting.rs:6:5: 6:10
- debug x => _5; // in scope 2 at $DIR/issue-76997-inline-scopes-parenting.rs:+1:14: +1:15
- let _6: (); // in scope 2 at $DIR/issue-76997-inline-scopes-parenting.rs:+1:23: +1:24
+ debug f => _1; // in scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:9: +1:10
+ scope 2 (inlined main::{closure#0}) { // at $DIR/issue_76997_inline_scopes_parenting.rs:6:5: 6:10
+ debug x => _5; // in scope 2 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:14: +1:15
+ let _6: (); // in scope 2 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:23: +1:24
scope 3 {
- debug y => _6; // in scope 3 at $DIR/issue-76997-inline-scopes-parenting.rs:+1:23: +1:24
+ debug y => _6; // in scope 3 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:23: +1:24
}
}
}
bb0: {
- StorageLive(_1); // scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+1:9: +1:10
- Deinit(_1); // scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+1:13: +1:33
- StorageLive(_2); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:5: +2:6
- _2 = &_1; // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:5: +2:6
- StorageLive(_3); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:5: +2:10
- StorageLive(_4); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:7: +2:9
- Deinit(_4); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:7: +2:9
- Deinit(_3); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:5: +2:10
- (_3.0: ()) = move _4; // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:5: +2:10
- StorageLive(_5); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:5: +2:10
- _5 = move (_3.0: ()); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:5: +2:10
- StorageLive(_6); // scope 2 at $DIR/issue-76997-inline-scopes-parenting.rs:+1:23: +1:24
- StorageDead(_6); // scope 2 at $DIR/issue-76997-inline-scopes-parenting.rs:+1:32: +1:33
- StorageDead(_5); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:5: +2:10
- StorageDead(_4); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:9: +2:10
- StorageDead(_3); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:9: +2:10
- StorageDead(_2); // scope 1 at $DIR/issue-76997-inline-scopes-parenting.rs:+2:9: +2:10
- StorageDead(_1); // scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+3:1: +3:2
- return; // scope 0 at $DIR/issue-76997-inline-scopes-parenting.rs:+3:2: +3:2
+ StorageLive(_1); // scope 0 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:9: +1:10
+ Deinit(_1); // scope 0 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:13: +1:33
+ StorageLive(_2); // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:6
+ _2 = &_1; // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:6
+ StorageLive(_3); // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:10
+ StorageLive(_4); // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:7: +2:9
+ Deinit(_4); // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:7: +2:9
+ Deinit(_3); // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:10
+ (_3.0: ()) = move _4; // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:10
+ StorageLive(_5); // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:10
+ _5 = move (_3.0: ()); // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:10
+ StorageLive(_6); // scope 2 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:23: +1:24
+ StorageDead(_6); // scope 2 at $DIR/issue_76997_inline_scopes_parenting.rs:+1:32: +1:33
+ StorageDead(_5); // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:5: +2:10
+ StorageDead(_4); // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:9: +2:10
+ StorageDead(_3); // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:9: +2:10
+ StorageDead(_2); // scope 1 at $DIR/issue_76997_inline_scopes_parenting.rs:+2:9: +2:10
+ StorageDead(_1); // scope 0 at $DIR/issue_76997_inline_scopes_parenting.rs:+3:1: +3:2
+ return; // scope 0 at $DIR/issue_76997_inline_scopes_parenting.rs:+3:2: +3:2
}
}
--- /dev/null
+// Tests that MIR inliner can handle `SourceScopeData` parenting correctly. (#76997)
+
+// EMIT_MIR issue_76997_inline_scopes_parenting.main.Inline.after.mir
+fn main() {
+ let f = |x| { let y = x; y };
+ f(())
+}
+ // MIR for `bar` after Inline
fn bar(_1: P) -> () {
- debug _baz => _1; // in scope 0 at $DIR/issue-78442.rs:+2:5: +2:9
- let mut _0: (); // return place in scope 0 at $DIR/issue-78442.rs:+3:3: +3:3
- let _2: (); // in scope 0 at $DIR/issue-78442.rs:+4:5: +4:17
- let mut _3: &fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:+4:5: +4:15
- let _4: fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:+4:5: +4:15
- let mut _5: (); // in scope 0 at $DIR/issue-78442.rs:+4:5: +4:17
-+ scope 1 (inlined <fn() {foo} as Fn<()>>::call - shim(fn() {foo})) { // at $DIR/issue-78442.rs:11:5: 11:17
+ debug _baz => _1; // in scope 0 at $DIR/issue_78442.rs:+2:5: +2:9
+ let mut _0: (); // return place in scope 0 at $DIR/issue_78442.rs:+3:3: +3:3
+ let _2: (); // in scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
+ let mut _3: &fn() {foo}; // in scope 0 at $DIR/issue_78442.rs:+4:5: +4:15
+ let _4: fn() {foo}; // in scope 0 at $DIR/issue_78442.rs:+4:5: +4:15
+ let mut _5: (); // in scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
++ scope 1 (inlined <fn() {foo} as Fn<()>>::call - shim(fn() {foo})) { // at $DIR/issue_78442.rs:11:5: 11:17
+ }
bb0: {
- StorageLive(_2); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17
- StorageLive(_3); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15
- StorageLive(_4); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15
-- _4 = hide_foo() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15
-+ _4 = hide_foo() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15
+ StorageLive(_2); // scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
+ StorageLive(_3); // scope 0 at $DIR/issue_78442.rs:+4:5: +4:15
+ StorageLive(_4); // scope 0 at $DIR/issue_78442.rs:+4:5: +4:15
+- _4 = hide_foo() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue_78442.rs:+4:5: +4:15
++ _4 = hide_foo() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue_78442.rs:+4:5: +4:15
// mir::Constant
- // + span: $DIR/issue-78442.rs:11:5: 11:13
+ // + span: $DIR/issue_78442.rs:11:5: 11:13
// + literal: Const { ty: fn() -> impl Fn() {hide_foo}, val: Value(<ZST>) }
}
bb1: {
- _3 = &_4; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15
- StorageLive(_5); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17
- Deinit(_5); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17
-- _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17
+ _3 = &_4; // scope 0 at $DIR/issue_78442.rs:+4:5: +4:15
+ StorageLive(_5); // scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
+ Deinit(_5); // scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
+- _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
- // mir::Constant
-- // + span: $DIR/issue-78442.rs:11:5: 11:15
+- // + span: $DIR/issue_78442.rs:11:5: 11:15
- // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() {foo}, ()) -> <fn() {foo} as FnOnce<()>>::Output {<fn() {foo} as Fn<()>>::call}, val: Value(<ZST>) }
+ _2 = move (*_3)() -> [return: bb5, unwind: bb3]; // scope 1 at $SRC_DIR/core/src/ops/function.rs:LL:COL
}
bb2: {
-- StorageDead(_5); // scope 0 at $DIR/issue-78442.rs:+4:16: +4:17
-- StorageDead(_3); // scope 0 at $DIR/issue-78442.rs:+4:16: +4:17
-- StorageDead(_4); // scope 0 at $DIR/issue-78442.rs:+4:17: +4:18
-- StorageDead(_2); // scope 0 at $DIR/issue-78442.rs:+4:17: +4:18
-- _0 = const (); // scope 0 at $DIR/issue-78442.rs:+3:3: +5:2
-- drop(_1) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/issue-78442.rs:+5:1: +5:2
-+ return; // scope 0 at $DIR/issue-78442.rs:+5:2: +5:2
+- StorageDead(_5); // scope 0 at $DIR/issue_78442.rs:+4:16: +4:17
+- StorageDead(_3); // scope 0 at $DIR/issue_78442.rs:+4:16: +4:17
+- StorageDead(_4); // scope 0 at $DIR/issue_78442.rs:+4:17: +4:18
+- StorageDead(_2); // scope 0 at $DIR/issue_78442.rs:+4:17: +4:18
+- _0 = const (); // scope 0 at $DIR/issue_78442.rs:+3:3: +5:2
+- drop(_1) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/issue_78442.rs:+5:1: +5:2
++ return; // scope 0 at $DIR/issue_78442.rs:+5:2: +5:2
}
- bb3: {
-- return; // scope 0 at $DIR/issue-78442.rs:+5:2: +5:2
+- return; // scope 0 at $DIR/issue_78442.rs:+5:2: +5:2
+ bb3 (cleanup): {
-+ drop(_1) -> bb4; // scope 0 at $DIR/issue-78442.rs:+5:1: +5:2
++ drop(_1) -> bb4; // scope 0 at $DIR/issue_78442.rs:+5:1: +5:2
}
bb4 (cleanup): {
-- drop(_1) -> bb5; // scope 0 at $DIR/issue-78442.rs:+5:1: +5:2
-+ resume; // scope 0 at $DIR/issue-78442.rs:+0:1: +5:2
+- drop(_1) -> bb5; // scope 0 at $DIR/issue_78442.rs:+5:1: +5:2
++ resume; // scope 0 at $DIR/issue_78442.rs:+0:1: +5:2
}
- bb5 (cleanup): {
-- resume; // scope 0 at $DIR/issue-78442.rs:+0:1: +5:2
+- resume; // scope 0 at $DIR/issue_78442.rs:+0:1: +5:2
+ bb5: {
-+ StorageDead(_5); // scope 0 at $DIR/issue-78442.rs:+4:16: +4:17
-+ StorageDead(_3); // scope 0 at $DIR/issue-78442.rs:+4:16: +4:17
-+ StorageDead(_4); // scope 0 at $DIR/issue-78442.rs:+4:17: +4:18
-+ StorageDead(_2); // scope 0 at $DIR/issue-78442.rs:+4:17: +4:18
-+ _0 = const (); // scope 0 at $DIR/issue-78442.rs:+3:3: +5:2
-+ drop(_1) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:+5:1: +5:2
++ StorageDead(_5); // scope 0 at $DIR/issue_78442.rs:+4:16: +4:17
++ StorageDead(_3); // scope 0 at $DIR/issue_78442.rs:+4:16: +4:17
++ StorageDead(_4); // scope 0 at $DIR/issue_78442.rs:+4:17: +4:18
++ StorageDead(_2); // scope 0 at $DIR/issue_78442.rs:+4:17: +4:18
++ _0 = const (); // scope 0 at $DIR/issue_78442.rs:+3:3: +5:2
++ drop(_1) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue_78442.rs:+5:1: +5:2
}
}
+ // MIR for `bar` after RevealAll
fn bar(_1: P) -> () {
- debug _baz => _1; // in scope 0 at $DIR/issue-78442.rs:+2:5: +2:9
- let mut _0: (); // return place in scope 0 at $DIR/issue-78442.rs:+3:3: +3:3
- let _2: (); // in scope 0 at $DIR/issue-78442.rs:+4:5: +4:17
-- let mut _3: &impl Fn(); // in scope 0 at $DIR/issue-78442.rs:+4:5: +4:15
-- let _4: impl Fn(); // in scope 0 at $DIR/issue-78442.rs:+4:5: +4:15
-+ let mut _3: &fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:+4:5: +4:15
-+ let _4: fn() {foo}; // in scope 0 at $DIR/issue-78442.rs:+4:5: +4:15
- let mut _5: (); // in scope 0 at $DIR/issue-78442.rs:+4:5: +4:17
+ debug _baz => _1; // in scope 0 at $DIR/issue_78442.rs:+2:5: +2:9
+ let mut _0: (); // return place in scope 0 at $DIR/issue_78442.rs:+3:3: +3:3
+ let _2: (); // in scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
+- let mut _3: &impl Fn(); // in scope 0 at $DIR/issue_78442.rs:+4:5: +4:15
+- let _4: impl Fn(); // in scope 0 at $DIR/issue_78442.rs:+4:5: +4:15
++ let mut _3: &fn() {foo}; // in scope 0 at $DIR/issue_78442.rs:+4:5: +4:15
++ let _4: fn() {foo}; // in scope 0 at $DIR/issue_78442.rs:+4:5: +4:15
+ let mut _5: (); // in scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
bb0: {
- StorageLive(_2); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17
- StorageLive(_3); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15
- StorageLive(_4); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15
- _4 = hide_foo() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15
+ StorageLive(_2); // scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
+ StorageLive(_3); // scope 0 at $DIR/issue_78442.rs:+4:5: +4:15
+ StorageLive(_4); // scope 0 at $DIR/issue_78442.rs:+4:5: +4:15
+ _4 = hide_foo() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue_78442.rs:+4:5: +4:15
// mir::Constant
- // + span: $DIR/issue-78442.rs:11:5: 11:13
+ // + span: $DIR/issue_78442.rs:11:5: 11:13
// + literal: Const { ty: fn() -> impl Fn() {hide_foo}, val: Value(<ZST>) }
}
bb1: {
- _3 = &_4; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:15
- StorageLive(_5); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17
- Deinit(_5); // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17
-- _2 = <impl Fn() as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17
-+ _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-78442.rs:+4:5: +4:17
+ _3 = &_4; // scope 0 at $DIR/issue_78442.rs:+4:5: +4:15
+ StorageLive(_5); // scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
+ Deinit(_5); // scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
+- _2 = <impl Fn() as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
++ _2 = <fn() {foo} as Fn<()>>::call(move _3, move _5) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue_78442.rs:+4:5: +4:17
// mir::Constant
- // + span: $DIR/issue-78442.rs:11:5: 11:15
+ // + span: $DIR/issue_78442.rs:11:5: 11:15
- // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(), ()) -> <impl Fn() as FnOnce<()>>::Output {<impl Fn() as Fn<()>>::call}, val: Value(<ZST>) }
+ // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a fn() {foo}, ()) -> <fn() {foo} as FnOnce<()>>::Output {<fn() {foo} as Fn<()>>::call}, val: Value(<ZST>) }
}
bb2: {
- StorageDead(_5); // scope 0 at $DIR/issue-78442.rs:+4:16: +4:17
- StorageDead(_3); // scope 0 at $DIR/issue-78442.rs:+4:16: +4:17
- StorageDead(_4); // scope 0 at $DIR/issue-78442.rs:+4:17: +4:18
- StorageDead(_2); // scope 0 at $DIR/issue-78442.rs:+4:17: +4:18
- _0 = const (); // scope 0 at $DIR/issue-78442.rs:+3:3: +5:2
- drop(_1) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/issue-78442.rs:+5:1: +5:2
+ StorageDead(_5); // scope 0 at $DIR/issue_78442.rs:+4:16: +4:17
+ StorageDead(_3); // scope 0 at $DIR/issue_78442.rs:+4:16: +4:17
+ StorageDead(_4); // scope 0 at $DIR/issue_78442.rs:+4:17: +4:18
+ StorageDead(_2); // scope 0 at $DIR/issue_78442.rs:+4:17: +4:18
+ _0 = const (); // scope 0 at $DIR/issue_78442.rs:+3:3: +5:2
+ drop(_1) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/issue_78442.rs:+5:1: +5:2
}
bb3: {
- return; // scope 0 at $DIR/issue-78442.rs:+5:2: +5:2
+ return; // scope 0 at $DIR/issue_78442.rs:+5:2: +5:2
}
bb4 (cleanup): {
- drop(_1) -> bb5; // scope 0 at $DIR/issue-78442.rs:+5:1: +5:2
+ drop(_1) -> bb5; // scope 0 at $DIR/issue_78442.rs:+5:1: +5:2
}
bb5 (cleanup): {
- resume; // scope 0 at $DIR/issue-78442.rs:+0:1: +5:2
+ resume; // scope 0 at $DIR/issue_78442.rs:+0:1: +5:2
}
}
--- /dev/null
+// compile-flags: -Z mir-opt-level=3 -Z inline-mir
+// ignore-wasm32-bare compiled with panic=abort by default
+#![crate_type = "lib"]
+
+// EMIT_MIR issue_78442.bar.RevealAll.diff
+// EMIT_MIR issue_78442.bar.Inline.diff
+pub fn bar<P>(
+ // Error won't happen if "bar" is not generic
+ _baz: P,
+) {
+ hide_foo()();
+}
+
+fn hide_foo() -> impl Fn() {
+ // Error won't happen if "iterate" hasn't impl Trait or has generics
+ foo
+}
+
+fn foo() { // Error won't happen if "foo" isn't used in "iterate" or has generics
+}
+++ /dev/null
-// Make sure that the MIR inliner does not loop indefinitely on polymorphic recursion.
-// compile-flags: --crate-type lib
-
-// Randomize `def_path_hash` by defining them under a module with different names
-macro_rules! emit {
- ($($m:ident)*) => {$(
- pub mod $m {
- pub trait Tr { type Next: Tr; }
-
- pub fn hoge<const N: usize, T: Tr>() {
- inner::<N, T>();
- }
-
- #[inline(always)]
- fn inner<const N: usize, T: Tr>()
- {
- inner::<N, T::Next>();
- inner::<N, T::Next>();
- }
- }
- )*};
-}
-
-// Increase the chance of triggering the bug
-emit!(m00 m01 m02 m03 m04 m05 m06 m07 m08 m09 m10 m11 m12 m13 m14 m15 m16 m17 m18 m19);
--- /dev/null
+// Make sure that the MIR inliner does not loop indefinitely on polymorphic recursion.
+// compile-flags: --crate-type lib
+
+// Randomize `def_path_hash` by defining them under a module with different names
+macro_rules! emit {
+ ($($m:ident)*) => {$(
+ pub mod $m {
+ pub trait Tr { type Next: Tr; }
+
+ pub fn hoge<const N: usize, T: Tr>() {
+ inner::<N, T>();
+ }
+
+ #[inline(always)]
+ fn inner<const N: usize, T: Tr>()
+ {
+ inner::<N, T::Next>();
+ inner::<N, T::Next>();
+ }
+ }
+ )*};
+}
+
+// Increase the chance of triggering the bug
+emit!(m00 m01 m02 m03 m04 m05 m06 m07 m08 m09 m10 m11 m12 m13 m14 m15 m16 m17 m18 m19);
+++ /dev/null
-// EMIT_MIR issue_101867.main.mir_map.0.mir
-fn main() {
- let x: Option<u8> = Some(1);
- let Some(y) = x else {
- panic!();
- };
-}
+++ /dev/null
-// compile-flags: -O -C debug-assertions=on
-// This needs inlining followed by ConstProp to reproduce, so we cannot use "unit-test".
-
-#[inline]
-pub fn imm8(x: u32) -> u32 {
- let mut out = 0u32;
- out |= (x >> 0) & 0xff;
- out
-}
-
-// EMIT_MIR issue_101973.inner.ConstProp.diff
-#[inline(never)]
-pub fn inner(fields: u32) -> i64 {
- imm8(fields).rotate_right(((fields >> 8) & 0xf) << 1) as i32 as i64
-}
-
-fn main() {
- let val = inner(0xe32cf20f);
- assert_eq!(val as u64, 0xfffffffff0000000);
-}
+++ /dev/null
-// check that we don't StorageDead booleans before they are used
-
-// EMIT_MIR issue_38669.main.SimplifyCfg-initial.after.mir
-fn main() {
- let mut should_break = false;
- loop {
- if should_break {
- break;
- }
- should_break = true;
- }
-}
+++ /dev/null
-// ignore-wasm32-bare compiled with panic=abort by default
-
-// check that we don't emit multiple drop flags when they are not needed.
-
-
-// EMIT_MIR issue_41110.main.ElaborateDrops.after.mir
-fn main() {
- let x = S.other(S.id());
-}
-
-// no_mangle to make sure this gets instantiated even in an executable.
-#[no_mangle]
-// EMIT_MIR issue_41110.test.ElaborateDrops.after.mir
-pub fn test() {
- let u = S;
- let mut v = S;
- drop(v);
- v = u;
-}
-
-struct S;
-impl Drop for S {
- fn drop(&mut self) {
- }
-}
-
-impl S {
- fn id(self) -> Self { self }
- fn other(self, s: Self) {}
-}
+++ /dev/null
-// Regression test for #41697. Using dump-mir was triggering
-// artificial cycles: during type-checking, we had to get the MIR for
-// the constant expressions in `[u8; 2]`, which in turn would trigger
-// an attempt to get the def-path, which in turn would request the
-// types of the impl, which would trigger a cycle. We suppressed this
-// cycle now by forcing mir-dump to avoid asking for types of an impl.
-
-#![feature(rustc_attrs)]
-
-use std::sync::Arc;
-
-trait Foo {
- fn get(&self) -> [u8; 2];
-}
-
-
-// EMIT_MIR issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir
-impl Foo for [u8; 1+1] {
- fn get(&self) -> [u8; 2] {
- *self
- }
-}
-
-struct Bar<T: ?Sized>(T);
-
-fn unsize_fat_ptr<'a>(x: &'a Bar<Foo + Send + 'a>) -> &'a Bar<Foo + 'a> {
- x
-}
-
-fn unsize_nested_fat_ptr(x: Arc<Foo + Send>) -> Arc<Foo> {
- x
-}
-
-fn main() {
- let x: Box<Bar<Foo + Send>> = Box::new(Bar([1,2]));
- assert_eq!(unsize_fat_ptr(&*x).0.get(), [1, 2]);
-
- let x: Arc<Foo + Send> = Arc::new([3, 4]);
- assert_eq!(unsize_nested_fat_ptr(x).get(), [3, 4]);
-}
+++ /dev/null
-// ignore-wasm32-bare compiled with panic=abort by default
-// check that we clear the "ADT master drop flag" even when there are
-// no fields to be dropped.
-
-// EMIT_MIR issue_41888.main.ElaborateDrops.after.mir
-fn main() {
- let e;
- if cond() {
- e = E::F(K);
- if let E::F(_k) = e {
- // older versions of rustc used to not clear the
- // drop flag for `e` in this path.
- }
- }
-}
-
-fn cond() -> bool { false }
-
-struct K;
-
-enum E {
- F(K),
- G(Box<E>)
-}
+++ /dev/null
-// We must mark a variable whose initialization fails due to an
-// abort statement as StorageDead.
-
-// EMIT_MIR issue_49232.main.mir_map.0.mir
-fn main() {
- loop {
- let beacon = {
- match true {
- false => 4,
- true => break,
- }
- };
- drop(&beacon);
- }
-}
+++ /dev/null
-// check that we don't forget to drop the Box if we early return before
-// initializing it
-// ignore-wasm32-bare compiled with panic=abort by default
-
-#![feature(box_syntax)]
-
-// EMIT_MIR issue_62289.test.ElaborateDrops.before.mir
-fn test() -> Option<Box<u32>> {
- Some(box (None?))
-}
-
-fn main() {
- test();
-}
+++ /dev/null
-// compile-flags: -Z mir-opt-level=1
-// Regression test for #72181, this ICE requires `-Z mir-opt-level=1` flags.
-
-#![feature(never_type)]
-#![allow(unused, invalid_value)]
-
-enum Void {}
-
-// EMIT_MIR issue_72181_1.f.mir_map.0.mir
-fn f(v: Void) -> ! {
- match v {}
-}
-
-// EMIT_MIR issue_72181_1.main.mir_map.0.mir
-fn main() {
- let v: Void = unsafe {
- std::mem::transmute::<(), Void>(())
- };
-
- f(v);
-}
+++ /dev/null
-// compile-flags: -Z mir-opt-level=1
-// Regression test for #72181, this ICE requires `-Z mir-opt-level=1` flags.
-
-use std::mem;
-
-#[derive(Copy, Clone)]
-enum Never {}
-
-union Foo {
- a: u64,
- b: Never
-}
-
-
-// EMIT_MIR issue_72181.foo.mir_map.0.mir
-fn foo(xs: [(Never, u32); 1]) -> u32 { xs[0].1 }
-
-// EMIT_MIR issue_72181.bar.mir_map.0.mir
-fn bar([(_, x)]: [(Never, u32); 1]) -> u32 { x }
-
-
-// EMIT_MIR issue_72181.main.mir_map.0.mir
-fn main() {
- let _ = mem::size_of::<Foo>();
-
- let f = [Foo { a: 42 }, Foo { a: 10 }];
- let _ = unsafe { f[0].a };
-}
+++ /dev/null
-fn main() {
- let split = match Some(1) {
- Some(v) => v,
- None => return,
- };
-
- let _prev = Some(split);
- assert_eq!(split, 1);
-}
-
-
-// EMIT_MIR issue_73223.main.SimplifyArmIdentity.diff
+++ /dev/null
-// compile-flags: -Zmir-opt-level=1 -Zinline-mir
-pub fn f<T>(a: &T) -> *const T {
- let b: &*const T = &(a as *const T);
- *b
-}
-
-fn main() {
- f(&2);
-}
-
-// EMIT_MIR issue_78192.f.InstCombine.diff
+++ /dev/null
-// compile-flags: -Z mir-opt-level=0
-// EMIT_MIR issue_91633.hey.mir_map.0.mir
-fn hey<T> (it: &[T])
- where
- [T] : std::ops::Index<usize>,
- {
- let _ = &it[0];
- }
-
-// EMIT_MIR issue_91633.bar.mir_map.0.mir
-fn bar<T> (it: Box<[T]>)
- where
- [T] : std::ops::Index<usize>,
- {
- let _ = it[0];
- }
-
-// EMIT_MIR issue_91633.fun.mir_map.0.mir
-fn fun<T> (it: &[T]) -> &T
- {
- let f = &it[0];
- f
- }
-
-// EMIT_MIR issue_91633.foo.mir_map.0.mir
-fn foo<T: Clone> (it: Box<[T]>) -> T
- {
- let f = it[0].clone();
- f
- }
- fn main(){}
+++ /dev/null
-#![feature(adt_const_params)]
-#![allow(incomplete_features)]
-
-pub fn function_with_bytes<const BYTES: &'static [u8; 4]>() -> &'static [u8] {
- BYTES
-}
-
-// EMIT_MIR issue_99325.main.mir_map.0.mir
-pub fn main() {
- assert_eq!(function_with_bytes::<b"AAAA">(), &[0x41, 0x41, 0x41, 0x41]);
- assert_eq!(function_with_bytes::<{ &[0x41, 0x41, 0x41, 0x41] }>(), b"AAAA");
-}
+++ /dev/null
-// MIR for `main` 0 mir_map
-
-| User Type Annotations
-| 0: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(std::option::Option<u8>) }, span: $DIR/issue-101867.rs:3:12: 3:22, inferred_ty: std::option::Option<u8>
-| 1: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(std::option::Option<u8>) }, span: $DIR/issue-101867.rs:3:12: 3:22, inferred_ty: std::option::Option<u8>
-|
-fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/issue-101867.rs:+0:11: +0:11
- let _1: std::option::Option<u8> as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/issue-101867.rs:+1:9: +1:10
- let mut _2: !; // in scope 0 at $DIR/issue-101867.rs:+2:26: +4:6
- let _3: (); // in scope 0 at $SRC_DIR/std/src/panic.rs:LL:COL
- let mut _4: !; // in scope 0 at $SRC_DIR/std/src/panic.rs:LL:COL
- let mut _6: isize; // in scope 0 at $DIR/issue-101867.rs:+2:9: +2:16
- scope 1 {
- debug x => _1; // in scope 1 at $DIR/issue-101867.rs:+1:9: +1:10
- let _5: u8; // in scope 1 at $DIR/issue-101867.rs:+2:14: +2:15
- scope 2 {
- debug y => _5; // in scope 2 at $DIR/issue-101867.rs:+2:14: +2:15
- }
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/issue-101867.rs:+1:9: +1:10
- _1 = Option::<u8>::Some(const 1_u8); // scope 0 at $DIR/issue-101867.rs:+1:25: +1:32
- FakeRead(ForLet(None), _1); // scope 0 at $DIR/issue-101867.rs:+1:9: +1:10
- AscribeUserType(_1, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 0 at $DIR/issue-101867.rs:+1:12: +1:22
- StorageLive(_5); // scope 1 at $DIR/issue-101867.rs:+2:14: +2:15
- FakeRead(ForMatchedPlace(None), _1); // scope 1 at $DIR/issue-101867.rs:+2:19: +2:20
- _6 = discriminant(_1); // scope 1 at $DIR/issue-101867.rs:+2:19: +2:20
- switchInt(move _6) -> [1_isize: bb4, otherwise: bb3]; // scope 1 at $DIR/issue-101867.rs:+2:9: +2:16
- }
-
- bb1: {
- StorageLive(_3); // scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL
- StorageLive(_4); // scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL
- _4 = begin_panic::<&str>(const "explicit panic") -> bb7; // scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL
- // mir::Constant
- // + span: $SRC_DIR/std/src/panic.rs:LL:COL
- // + literal: Const { ty: fn(&str) -> ! {begin_panic::<&str>}, val: Value(<ZST>) }
- // mir::Constant
- // + span: $SRC_DIR/std/src/panic.rs:LL:COL
- // + literal: Const { ty: &str, val: Value(Slice(..)) }
- }
-
- bb2: {
- StorageDead(_4); // scope 1 at $SRC_DIR/std/src/panic.rs:LL:COL
- StorageDead(_3); // scope 1 at $DIR/issue-101867.rs:+3:16: +3:17
- unreachable; // scope 1 at $DIR/issue-101867.rs:+2:26: +4:6
- }
-
- bb3: {
- goto -> bb6; // scope 1 at $DIR/issue-101867.rs:+2:19: +2:20
- }
-
- bb4: {
- falseEdge -> [real: bb5, imaginary: bb3]; // scope 1 at $DIR/issue-101867.rs:+2:9: +2:16
- }
-
- bb5: {
- _5 = ((_1 as Some).0: u8); // scope 1 at $DIR/issue-101867.rs:+2:14: +2:15
- _0 = const (); // scope 0 at $DIR/issue-101867.rs:+0:11: +5:2
- StorageDead(_5); // scope 1 at $DIR/issue-101867.rs:+5:1: +5:2
- StorageDead(_1); // scope 0 at $DIR/issue-101867.rs:+5:1: +5:2
- return; // scope 0 at $DIR/issue-101867.rs:+5:2: +5:2
- }
-
- bb6: {
- StorageDead(_5); // scope 1 at $DIR/issue-101867.rs:+5:1: +5:2
- goto -> bb1; // scope 0 at $DIR/issue-101867.rs:+0:11: +5:2
- }
-
- bb7 (cleanup): {
- resume; // scope 0 at $DIR/issue-101867.rs:+0:1: +5:2
- }
-}
+ // MIR for `inner` after ConstProp
fn inner(_1: u32) -> i64 {
- debug fields => _1; // in scope 0 at $DIR/issue-101973.rs:+0:14: +0:20
- let mut _0: i64; // return place in scope 0 at $DIR/issue-101973.rs:+0:30: +0:33
- let mut _2: i32; // in scope 0 at $DIR/issue-101973.rs:+1:5: +1:65
- let mut _3: u32; // in scope 0 at $DIR/issue-101973.rs:+1:5: +1:58
- let mut _4: u32; // in scope 0 at $DIR/issue-101973.rs:+1:5: +1:17
- let mut _5: u32; // in scope 0 at $DIR/issue-101973.rs:+1:10: +1:16
- let mut _6: u32; // in scope 0 at $DIR/issue-101973.rs:+1:31: +1:57
- let mut _7: u32; // in scope 0 at $DIR/issue-101973.rs:+1:31: +1:52
- let mut _8: u32; // in scope 0 at $DIR/issue-101973.rs:+1:32: +1:45
- let mut _9: u32; // in scope 0 at $DIR/issue-101973.rs:+1:33: +1:39
- let mut _10: (u32, bool); // in scope 0 at $DIR/issue-101973.rs:+1:32: +1:45
- let mut _11: (u32, bool); // in scope 0 at $DIR/issue-101973.rs:+1:31: +1:57
- scope 1 (inlined imm8) { // at $DIR/issue-101973.rs:14:5: 14:17
- debug x => _5; // in scope 1 at $DIR/issue-101973.rs:5:13: 5:14
- let mut _12: u32; // in scope 1 at $DIR/issue-101973.rs:7:12: 7:27
- let mut _13: u32; // in scope 1 at $DIR/issue-101973.rs:7:12: 7:20
- let mut _14: u32; // in scope 1 at $DIR/issue-101973.rs:7:13: 7:14
- let mut _15: (u32, bool); // in scope 1 at $DIR/issue-101973.rs:7:12: 7:20
+ debug fields => _1; // in scope 0 at $DIR/issue_101973.rs:+0:14: +0:20
+ let mut _0: i64; // return place in scope 0 at $DIR/issue_101973.rs:+0:30: +0:33
+ let mut _2: i32; // in scope 0 at $DIR/issue_101973.rs:+1:5: +1:65
+ let mut _3: u32; // in scope 0 at $DIR/issue_101973.rs:+1:5: +1:58
+ let mut _4: u32; // in scope 0 at $DIR/issue_101973.rs:+1:5: +1:17
+ let mut _5: u32; // in scope 0 at $DIR/issue_101973.rs:+1:10: +1:16
+ let mut _6: u32; // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
+ let mut _7: u32; // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:52
+ let mut _8: u32; // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
+ let mut _9: u32; // in scope 0 at $DIR/issue_101973.rs:+1:33: +1:39
+ let mut _10: (u32, bool); // in scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
+ let mut _11: (u32, bool); // in scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
+ scope 1 (inlined imm8) { // at $DIR/issue_101973.rs:14:5: 14:17
+ debug x => _5; // in scope 1 at $DIR/issue_101973.rs:5:13: 5:14
+ let mut _12: u32; // in scope 1 at $DIR/issue_101973.rs:7:12: 7:27
+ let mut _13: u32; // in scope 1 at $DIR/issue_101973.rs:7:12: 7:20
+ let mut _14: u32; // in scope 1 at $DIR/issue_101973.rs:7:13: 7:14
+ let mut _15: (u32, bool); // in scope 1 at $DIR/issue_101973.rs:7:12: 7:20
scope 2 {
- debug out => _4; // in scope 2 at $DIR/issue-101973.rs:6:9: 6:16
+ debug out => _4; // in scope 2 at $DIR/issue_101973.rs:6:9: 6:16
}
}
- scope 3 (inlined core::num::<impl u32>::rotate_right) { // at $DIR/issue-101973.rs:14:5: 14:58
+ scope 3 (inlined core::num::<impl u32>::rotate_right) { // at $DIR/issue_101973.rs:14:5: 14:58
debug self => _4; // in scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
debug n => _6; // in scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
let mut _16: u32; // in scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
}
bb0: {
- StorageLive(_2); // scope 0 at $DIR/issue-101973.rs:+1:5: +1:65
- StorageLive(_3); // scope 0 at $DIR/issue-101973.rs:+1:5: +1:58
- StorageLive(_4); // scope 0 at $DIR/issue-101973.rs:+1:5: +1:17
- StorageLive(_5); // scope 0 at $DIR/issue-101973.rs:+1:10: +1:16
- _5 = _1; // scope 0 at $DIR/issue-101973.rs:+1:10: +1:16
- _4 = const 0_u32; // scope 1 at $DIR/issue-101973.rs:6:19: 6:23
- StorageLive(_12); // scope 2 at $DIR/issue-101973.rs:7:12: 7:27
- StorageLive(_13); // scope 2 at $DIR/issue-101973.rs:7:12: 7:20
- StorageLive(_14); // scope 2 at $DIR/issue-101973.rs:7:13: 7:14
- _14 = _5; // scope 2 at $DIR/issue-101973.rs:7:13: 7:14
- _15 = CheckedShr(_14, const 0_i32); // scope 2 at $DIR/issue-101973.rs:7:12: 7:20
- assert(!move (_15.1: bool), "attempt to shift right by `{}`, which would overflow", const 0_i32) -> bb3; // scope 2 at $DIR/issue-101973.rs:7:12: 7:20
+ StorageLive(_2); // scope 0 at $DIR/issue_101973.rs:+1:5: +1:65
+ StorageLive(_3); // scope 0 at $DIR/issue_101973.rs:+1:5: +1:58
+ StorageLive(_4); // scope 0 at $DIR/issue_101973.rs:+1:5: +1:17
+ StorageLive(_5); // scope 0 at $DIR/issue_101973.rs:+1:10: +1:16
+ _5 = _1; // scope 0 at $DIR/issue_101973.rs:+1:10: +1:16
+ _4 = const 0_u32; // scope 1 at $DIR/issue_101973.rs:6:19: 6:23
+ StorageLive(_12); // scope 2 at $DIR/issue_101973.rs:7:12: 7:27
+ StorageLive(_13); // scope 2 at $DIR/issue_101973.rs:7:12: 7:20
+ StorageLive(_14); // scope 2 at $DIR/issue_101973.rs:7:13: 7:14
+ _14 = _5; // scope 2 at $DIR/issue_101973.rs:7:13: 7:14
+ _15 = CheckedShr(_14, const 0_i32); // scope 2 at $DIR/issue_101973.rs:7:12: 7:20
+ assert(!move (_15.1: bool), "attempt to shift right by `{}`, which would overflow", const 0_i32) -> bb3; // scope 2 at $DIR/issue_101973.rs:7:12: 7:20
}
bb1: {
- _8 = move (_10.0: u32); // scope 0 at $DIR/issue-101973.rs:+1:32: +1:45
- StorageDead(_9); // scope 0 at $DIR/issue-101973.rs:+1:44: +1:45
- _7 = BitAnd(move _8, const 15_u32); // scope 0 at $DIR/issue-101973.rs:+1:31: +1:52
- StorageDead(_8); // scope 0 at $DIR/issue-101973.rs:+1:51: +1:52
- _11 = CheckedShl(_7, const 1_i32); // scope 0 at $DIR/issue-101973.rs:+1:31: +1:57
- assert(!move (_11.1: bool), "attempt to shift left by `{}`, which would overflow", const 1_i32) -> bb2; // scope 0 at $DIR/issue-101973.rs:+1:31: +1:57
+ _8 = move (_10.0: u32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
+ StorageDead(_9); // scope 0 at $DIR/issue_101973.rs:+1:44: +1:45
+ _7 = BitAnd(move _8, const 15_u32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52
+ StorageDead(_8); // scope 0 at $DIR/issue_101973.rs:+1:51: +1:52
+ _11 = CheckedShl(_7, const 1_i32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
+ assert(!move (_11.1: bool), "attempt to shift left by `{}`, which would overflow", const 1_i32) -> bb2; // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
}
bb2: {
- _6 = move (_11.0: u32); // scope 0 at $DIR/issue-101973.rs:+1:31: +1:57
- StorageDead(_7); // scope 0 at $DIR/issue-101973.rs:+1:56: +1:57
+ _6 = move (_11.0: u32); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
+ StorageDead(_7); // scope 0 at $DIR/issue_101973.rs:+1:56: +1:57
StorageLive(_16); // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
_16 = _4; // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
StorageLive(_17); // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
}
bb3: {
- _13 = move (_15.0: u32); // scope 2 at $DIR/issue-101973.rs:7:12: 7:20
- StorageDead(_14); // scope 2 at $DIR/issue-101973.rs:7:19: 7:20
- _12 = BitAnd(move _13, const 255_u32); // scope 2 at $DIR/issue-101973.rs:7:12: 7:27
- StorageDead(_13); // scope 2 at $DIR/issue-101973.rs:7:26: 7:27
- _4 = BitOr(_4, move _12); // scope 2 at $DIR/issue-101973.rs:7:5: 7:27
- StorageDead(_12); // scope 2 at $DIR/issue-101973.rs:7:26: 7:27
- StorageDead(_5); // scope 0 at $DIR/issue-101973.rs:+1:16: +1:17
- StorageLive(_6); // scope 0 at $DIR/issue-101973.rs:+1:31: +1:57
- StorageLive(_7); // scope 0 at $DIR/issue-101973.rs:+1:31: +1:52
- StorageLive(_8); // scope 0 at $DIR/issue-101973.rs:+1:32: +1:45
- StorageLive(_9); // scope 0 at $DIR/issue-101973.rs:+1:33: +1:39
- _9 = _1; // scope 0 at $DIR/issue-101973.rs:+1:33: +1:39
- _10 = CheckedShr(_9, const 8_i32); // scope 0 at $DIR/issue-101973.rs:+1:32: +1:45
- assert(!move (_10.1: bool), "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue-101973.rs:+1:32: +1:45
+ _13 = move (_15.0: u32); // scope 2 at $DIR/issue_101973.rs:7:12: 7:20
+ StorageDead(_14); // scope 2 at $DIR/issue_101973.rs:7:19: 7:20
+ _12 = BitAnd(move _13, const 255_u32); // scope 2 at $DIR/issue_101973.rs:7:12: 7:27
+ StorageDead(_13); // scope 2 at $DIR/issue_101973.rs:7:26: 7:27
+ _4 = BitOr(_4, move _12); // scope 2 at $DIR/issue_101973.rs:7:5: 7:27
+ StorageDead(_12); // scope 2 at $DIR/issue_101973.rs:7:26: 7:27
+ StorageDead(_5); // scope 0 at $DIR/issue_101973.rs:+1:16: +1:17
+ StorageLive(_6); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:57
+ StorageLive(_7); // scope 0 at $DIR/issue_101973.rs:+1:31: +1:52
+ StorageLive(_8); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
+ StorageLive(_9); // scope 0 at $DIR/issue_101973.rs:+1:33: +1:39
+ _9 = _1; // scope 0 at $DIR/issue_101973.rs:+1:33: +1:39
+ _10 = CheckedShr(_9, const 8_i32); // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
+ assert(!move (_10.1: bool), "attempt to shift right by `{}`, which would overflow", const 8_i32) -> bb1; // scope 0 at $DIR/issue_101973.rs:+1:32: +1:45
}
bb4: {
StorageDead(_17); // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
StorageDead(_16); // scope 3 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL
- StorageDead(_6); // scope 0 at $DIR/issue-101973.rs:+1:57: +1:58
- StorageDead(_4); // scope 0 at $DIR/issue-101973.rs:+1:57: +1:58
- _2 = move _3 as i32 (IntToInt); // scope 0 at $DIR/issue-101973.rs:+1:5: +1:65
- StorageDead(_3); // scope 0 at $DIR/issue-101973.rs:+1:64: +1:65
- _0 = move _2 as i64 (IntToInt); // scope 0 at $DIR/issue-101973.rs:+1:5: +1:72
- StorageDead(_2); // scope 0 at $DIR/issue-101973.rs:+1:71: +1:72
- return; // scope 0 at $DIR/issue-101973.rs:+2:2: +2:2
+ StorageDead(_6); // scope 0 at $DIR/issue_101973.rs:+1:57: +1:58
+ StorageDead(_4); // scope 0 at $DIR/issue_101973.rs:+1:57: +1:58
+ _2 = move _3 as i32 (IntToInt); // scope 0 at $DIR/issue_101973.rs:+1:5: +1:65
+ StorageDead(_3); // scope 0 at $DIR/issue_101973.rs:+1:64: +1:65
+ _0 = move _2 as i64 (IntToInt); // scope 0 at $DIR/issue_101973.rs:+1:5: +1:72
+ StorageDead(_2); // scope 0 at $DIR/issue_101973.rs:+1:71: +1:72
+ return; // scope 0 at $DIR/issue_101973.rs:+2:2: +2:2
}
}
--- /dev/null
+// compile-flags: -O -C debug-assertions=on
+// This needs inlining followed by ConstProp to reproduce, so we cannot use "unit-test".
+
+#[inline]
+pub fn imm8(x: u32) -> u32 {
+ let mut out = 0u32;
+ out |= (x >> 0) & 0xff;
+ out
+}
+
+// EMIT_MIR issue_101973.inner.ConstProp.diff
+#[inline(never)]
+pub fn inner(fields: u32) -> i64 {
+ imm8(fields).rotate_right(((fields >> 8) & 0xf) << 1) as i32 as i64
+}
+
+fn main() {
+ let val = inner(0xe32cf20f);
+ assert_eq!(val as u64, 0xfffffffff0000000);
+}
// MIR for `main` after SimplifyCfg-initial
fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/issue-38669.rs:+0:11: +0:11
- let mut _1: bool; // in scope 0 at $DIR/issue-38669.rs:+1:9: +1:25
- let mut _2: (); // in scope 0 at $DIR/issue-38669.rs:+0:1: +8:2
- let _3: (); // in scope 0 at $DIR/issue-38669.rs:+3:9: +5:10
- let mut _4: bool; // in scope 0 at $DIR/issue-38669.rs:+3:12: +3:24
- let mut _5: !; // in scope 0 at $DIR/issue-38669.rs:+3:25: +5:10
+ let mut _0: (); // return place in scope 0 at $DIR/issue_38669.rs:+0:11: +0:11
+ let mut _1: bool; // in scope 0 at $DIR/issue_38669.rs:+1:9: +1:25
+ let mut _2: (); // in scope 0 at $DIR/issue_38669.rs:+0:1: +8:2
+ let _3: (); // in scope 0 at $DIR/issue_38669.rs:+3:9: +5:10
+ let mut _4: bool; // in scope 0 at $DIR/issue_38669.rs:+3:12: +3:24
+ let mut _5: !; // in scope 0 at $DIR/issue_38669.rs:+3:25: +5:10
scope 1 {
- debug should_break => _1; // in scope 1 at $DIR/issue-38669.rs:+1:9: +1:25
+ debug should_break => _1; // in scope 1 at $DIR/issue_38669.rs:+1:9: +1:25
}
bb0: {
- StorageLive(_1); // scope 0 at $DIR/issue-38669.rs:+1:9: +1:25
- _1 = const false; // scope 0 at $DIR/issue-38669.rs:+1:28: +1:33
- FakeRead(ForLet(None), _1); // scope 0 at $DIR/issue-38669.rs:+1:9: +1:25
- goto -> bb1; // scope 1 at $DIR/issue-38669.rs:+2:5: +7:6
+ StorageLive(_1); // scope 0 at $DIR/issue_38669.rs:+1:9: +1:25
+ _1 = const false; // scope 0 at $DIR/issue_38669.rs:+1:28: +1:33
+ FakeRead(ForLet(None), _1); // scope 0 at $DIR/issue_38669.rs:+1:9: +1:25
+ goto -> bb1; // scope 1 at $DIR/issue_38669.rs:+2:5: +7:6
}
bb1: {
- falseUnwind -> [real: bb2, cleanup: bb5]; // scope 1 at $DIR/issue-38669.rs:+2:5: +7:6
+ falseUnwind -> [real: bb2, cleanup: bb5]; // scope 1 at $DIR/issue_38669.rs:+2:5: +7:6
}
bb2: {
- StorageLive(_3); // scope 1 at $DIR/issue-38669.rs:+3:9: +5:10
- StorageLive(_4); // scope 1 at $DIR/issue-38669.rs:+3:12: +3:24
- _4 = _1; // scope 1 at $DIR/issue-38669.rs:+3:12: +3:24
- switchInt(move _4) -> [false: bb4, otherwise: bb3]; // scope 1 at $DIR/issue-38669.rs:+3:12: +3:24
+ StorageLive(_3); // scope 1 at $DIR/issue_38669.rs:+3:9: +5:10
+ StorageLive(_4); // scope 1 at $DIR/issue_38669.rs:+3:12: +3:24
+ _4 = _1; // scope 1 at $DIR/issue_38669.rs:+3:12: +3:24
+ switchInt(move _4) -> [false: bb4, otherwise: bb3]; // scope 1 at $DIR/issue_38669.rs:+3:12: +3:24
}
bb3: {
- _0 = const (); // scope 1 at $DIR/issue-38669.rs:+4:13: +4:18
- StorageDead(_4); // scope 1 at $DIR/issue-38669.rs:+5:9: +5:10
- StorageDead(_3); // scope 1 at $DIR/issue-38669.rs:+5:9: +5:10
- StorageDead(_1); // scope 0 at $DIR/issue-38669.rs:+8:1: +8:2
- return; // scope 0 at $DIR/issue-38669.rs:+8:2: +8:2
+ _0 = const (); // scope 1 at $DIR/issue_38669.rs:+4:13: +4:18
+ StorageDead(_4); // scope 1 at $DIR/issue_38669.rs:+5:9: +5:10
+ StorageDead(_3); // scope 1 at $DIR/issue_38669.rs:+5:9: +5:10
+ StorageDead(_1); // scope 0 at $DIR/issue_38669.rs:+8:1: +8:2
+ return; // scope 0 at $DIR/issue_38669.rs:+8:2: +8:2
}
bb4: {
- _3 = const (); // scope 1 at $DIR/issue-38669.rs:+5:10: +5:10
- StorageDead(_4); // scope 1 at $DIR/issue-38669.rs:+5:9: +5:10
- StorageDead(_3); // scope 1 at $DIR/issue-38669.rs:+5:9: +5:10
- _1 = const true; // scope 1 at $DIR/issue-38669.rs:+6:9: +6:28
- _2 = const (); // scope 1 at $DIR/issue-38669.rs:+2:10: +7:6
- goto -> bb1; // scope 1 at $DIR/issue-38669.rs:+2:5: +7:6
+ _3 = const (); // scope 1 at $DIR/issue_38669.rs:+5:10: +5:10
+ StorageDead(_4); // scope 1 at $DIR/issue_38669.rs:+5:9: +5:10
+ StorageDead(_3); // scope 1 at $DIR/issue_38669.rs:+5:9: +5:10
+ _1 = const true; // scope 1 at $DIR/issue_38669.rs:+6:9: +6:28
+ _2 = const (); // scope 1 at $DIR/issue_38669.rs:+2:10: +7:6
+ goto -> bb1; // scope 1 at $DIR/issue_38669.rs:+2:5: +7:6
}
bb5 (cleanup): {
- resume; // scope 0 at $DIR/issue-38669.rs:+0:1: +8:2
+ resume; // scope 0 at $DIR/issue_38669.rs:+0:1: +8:2
}
}
--- /dev/null
+// check that we don't StorageDead booleans before they are used
+
+// EMIT_MIR issue_38669.main.SimplifyCfg-initial.after.mir
+fn main() {
+ let mut should_break = false;
+ loop {
+ if should_break {
+ break;
+ }
+ should_break = true;
+ }
+}
// MIR for `main` after ElaborateDrops
fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/issue-41110.rs:+0:11: +0:11
- let _1: (); // in scope 0 at $DIR/issue-41110.rs:+1:9: +1:10
- let mut _2: S; // in scope 0 at $DIR/issue-41110.rs:+1:13: +1:14
- let mut _3: S; // in scope 0 at $DIR/issue-41110.rs:+1:21: +1:27
- let mut _4: S; // in scope 0 at $DIR/issue-41110.rs:+1:21: +1:22
- let mut _5: bool; // in scope 0 at $DIR/issue-41110.rs:+1:27: +1:28
+ let mut _0: (); // return place in scope 0 at $DIR/issue_41110.rs:+0:11: +0:11
+ let _1: (); // in scope 0 at $DIR/issue_41110.rs:+1:9: +1:10
+ let mut _2: S; // in scope 0 at $DIR/issue_41110.rs:+1:13: +1:14
+ let mut _3: S; // in scope 0 at $DIR/issue_41110.rs:+1:21: +1:27
+ let mut _4: S; // in scope 0 at $DIR/issue_41110.rs:+1:21: +1:22
+ let mut _5: bool; // in scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
scope 1 {
- debug x => _1; // in scope 1 at $DIR/issue-41110.rs:+1:9: +1:10
+ debug x => _1; // in scope 1 at $DIR/issue_41110.rs:+1:9: +1:10
}
bb0: {
- _5 = const false; // scope 0 at $DIR/issue-41110.rs:+1:9: +1:10
- StorageLive(_1); // scope 0 at $DIR/issue-41110.rs:+1:9: +1:10
- StorageLive(_2); // scope 0 at $DIR/issue-41110.rs:+1:13: +1:14
- _5 = const true; // scope 0 at $DIR/issue-41110.rs:+1:13: +1:14
- _2 = S; // scope 0 at $DIR/issue-41110.rs:+1:13: +1:14
- StorageLive(_3); // scope 0 at $DIR/issue-41110.rs:+1:21: +1:27
- StorageLive(_4); // scope 0 at $DIR/issue-41110.rs:+1:21: +1:22
- _4 = S; // scope 0 at $DIR/issue-41110.rs:+1:21: +1:22
- _3 = S::id(move _4) -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue-41110.rs:+1:21: +1:27
+ _5 = const false; // scope 0 at $DIR/issue_41110.rs:+1:9: +1:10
+ StorageLive(_1); // scope 0 at $DIR/issue_41110.rs:+1:9: +1:10
+ StorageLive(_2); // scope 0 at $DIR/issue_41110.rs:+1:13: +1:14
+ _5 = const true; // scope 0 at $DIR/issue_41110.rs:+1:13: +1:14
+ _2 = S; // scope 0 at $DIR/issue_41110.rs:+1:13: +1:14
+ StorageLive(_3); // scope 0 at $DIR/issue_41110.rs:+1:21: +1:27
+ StorageLive(_4); // scope 0 at $DIR/issue_41110.rs:+1:21: +1:22
+ _4 = S; // scope 0 at $DIR/issue_41110.rs:+1:21: +1:22
+ _3 = S::id(move _4) -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/issue_41110.rs:+1:21: +1:27
// mir::Constant
- // + span: $DIR/issue-41110.rs:8:23: 8:25
+ // + span: $DIR/issue_41110.rs:8:23: 8:25
// + literal: Const { ty: fn(S) -> S {S::id}, val: Value(<ZST>) }
}
bb1: {
- StorageDead(_4); // scope 0 at $DIR/issue-41110.rs:+1:26: +1:27
- _5 = const false; // scope 0 at $DIR/issue-41110.rs:+1:13: +1:28
- _1 = S::other(move _2, move _3) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/issue-41110.rs:+1:13: +1:28
+ StorageDead(_4); // scope 0 at $DIR/issue_41110.rs:+1:26: +1:27
+ _5 = const false; // scope 0 at $DIR/issue_41110.rs:+1:13: +1:28
+ _1 = S::other(move _2, move _3) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/issue_41110.rs:+1:13: +1:28
// mir::Constant
- // + span: $DIR/issue-41110.rs:8:15: 8:20
+ // + span: $DIR/issue_41110.rs:8:15: 8:20
// + literal: Const { ty: fn(S, S) {S::other}, val: Value(<ZST>) }
}
bb2: {
- StorageDead(_3); // scope 0 at $DIR/issue-41110.rs:+1:27: +1:28
- _5 = const false; // scope 0 at $DIR/issue-41110.rs:+1:27: +1:28
- StorageDead(_2); // scope 0 at $DIR/issue-41110.rs:+1:27: +1:28
- _0 = const (); // scope 0 at $DIR/issue-41110.rs:+0:11: +2:2
- StorageDead(_1); // scope 0 at $DIR/issue-41110.rs:+2:1: +2:2
- return; // scope 0 at $DIR/issue-41110.rs:+2:2: +2:2
+ StorageDead(_3); // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
+ _5 = const false; // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
+ StorageDead(_2); // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
+ _0 = const (); // scope 0 at $DIR/issue_41110.rs:+0:11: +2:2
+ StorageDead(_1); // scope 0 at $DIR/issue_41110.rs:+2:1: +2:2
+ return; // scope 0 at $DIR/issue_41110.rs:+2:2: +2:2
}
bb3 (cleanup): {
- goto -> bb5; // scope 0 at $DIR/issue-41110.rs:+1:27: +1:28
+ goto -> bb5; // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
}
bb4 (cleanup): {
- goto -> bb5; // scope 0 at $DIR/issue-41110.rs:+1:26: +1:27
+ goto -> bb5; // scope 0 at $DIR/issue_41110.rs:+1:26: +1:27
}
bb5 (cleanup): {
- goto -> bb8; // scope 0 at $DIR/issue-41110.rs:+1:27: +1:28
+ goto -> bb8; // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
}
bb6 (cleanup): {
- resume; // scope 0 at $DIR/issue-41110.rs:+0:1: +2:2
+ resume; // scope 0 at $DIR/issue_41110.rs:+0:1: +2:2
}
bb7 (cleanup): {
- drop(_2) -> bb6; // scope 0 at $DIR/issue-41110.rs:+1:27: +1:28
+ drop(_2) -> bb6; // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
}
bb8 (cleanup): {
- switchInt(_5) -> [false: bb6, otherwise: bb7]; // scope 0 at $DIR/issue-41110.rs:+1:27: +1:28
+ switchInt(_5) -> [false: bb6, otherwise: bb7]; // scope 0 at $DIR/issue_41110.rs:+1:27: +1:28
}
}
--- /dev/null
+// ignore-wasm32-bare compiled with panic=abort by default
+
+// check that we don't emit multiple drop flags when they are not needed.
+
+
+// EMIT_MIR issue_41110.main.ElaborateDrops.after.mir
+fn main() {
+ let x = S.other(S.id());
+}
+
+// no_mangle to make sure this gets instantiated even in an executable.
+#[no_mangle]
+// EMIT_MIR issue_41110.test.ElaborateDrops.after.mir
+pub fn test() {
+ let u = S;
+ let mut v = S;
+ drop(v);
+ v = u;
+}
+
+struct S;
+impl Drop for S {
+ fn drop(&mut self) {
+ }
+}
+
+impl S {
+ fn id(self) -> Self { self }
+ fn other(self, s: Self) {}
+}
// MIR for `test` after ElaborateDrops
fn test() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/issue-41110.rs:+0:15: +0:15
- let _1: S; // in scope 0 at $DIR/issue-41110.rs:+1:9: +1:10
- let _3: (); // in scope 0 at $DIR/issue-41110.rs:+3:5: +3:12
- let mut _4: S; // in scope 0 at $DIR/issue-41110.rs:+3:10: +3:11
- let mut _5: S; // in scope 0 at $DIR/issue-41110.rs:+4:9: +4:10
- let mut _6: bool; // in scope 0 at $DIR/issue-41110.rs:+5:1: +5:2
+ let mut _0: (); // return place in scope 0 at $DIR/issue_41110.rs:+0:15: +0:15
+ let _1: S; // in scope 0 at $DIR/issue_41110.rs:+1:9: +1:10
+ let _3: (); // in scope 0 at $DIR/issue_41110.rs:+3:5: +3:12
+ let mut _4: S; // in scope 0 at $DIR/issue_41110.rs:+3:10: +3:11
+ let mut _5: S; // in scope 0 at $DIR/issue_41110.rs:+4:9: +4:10
+ let mut _6: bool; // in scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
scope 1 {
- debug u => _1; // in scope 1 at $DIR/issue-41110.rs:+1:9: +1:10
- let mut _2: S; // in scope 1 at $DIR/issue-41110.rs:+2:9: +2:14
+ debug u => _1; // in scope 1 at $DIR/issue_41110.rs:+1:9: +1:10
+ let mut _2: S; // in scope 1 at $DIR/issue_41110.rs:+2:9: +2:14
scope 2 {
- debug v => _2; // in scope 2 at $DIR/issue-41110.rs:+2:9: +2:14
+ debug v => _2; // in scope 2 at $DIR/issue_41110.rs:+2:9: +2:14
}
}
bb0: {
- _6 = const false; // scope 0 at $DIR/issue-41110.rs:+1:9: +1:10
- StorageLive(_1); // scope 0 at $DIR/issue-41110.rs:+1:9: +1:10
- _6 = const true; // scope 0 at $DIR/issue-41110.rs:+1:13: +1:14
- _1 = S; // scope 0 at $DIR/issue-41110.rs:+1:13: +1:14
- StorageLive(_2); // scope 1 at $DIR/issue-41110.rs:+2:9: +2:14
- _2 = S; // scope 1 at $DIR/issue-41110.rs:+2:17: +2:18
- StorageLive(_3); // scope 2 at $DIR/issue-41110.rs:+3:5: +3:12
- StorageLive(_4); // scope 2 at $DIR/issue-41110.rs:+3:10: +3:11
- _4 = move _2; // scope 2 at $DIR/issue-41110.rs:+3:10: +3:11
- _3 = std::mem::drop::<S>(move _4) -> [return: bb1, unwind: bb7]; // scope 2 at $DIR/issue-41110.rs:+3:5: +3:12
+ _6 = const false; // scope 0 at $DIR/issue_41110.rs:+1:9: +1:10
+ StorageLive(_1); // scope 0 at $DIR/issue_41110.rs:+1:9: +1:10
+ _6 = const true; // scope 0 at $DIR/issue_41110.rs:+1:13: +1:14
+ _1 = S; // scope 0 at $DIR/issue_41110.rs:+1:13: +1:14
+ StorageLive(_2); // scope 1 at $DIR/issue_41110.rs:+2:9: +2:14
+ _2 = S; // scope 1 at $DIR/issue_41110.rs:+2:17: +2:18
+ StorageLive(_3); // scope 2 at $DIR/issue_41110.rs:+3:5: +3:12
+ StorageLive(_4); // scope 2 at $DIR/issue_41110.rs:+3:10: +3:11
+ _4 = move _2; // scope 2 at $DIR/issue_41110.rs:+3:10: +3:11
+ _3 = std::mem::drop::<S>(move _4) -> [return: bb1, unwind: bb7]; // scope 2 at $DIR/issue_41110.rs:+3:5: +3:12
// mir::Constant
- // + span: $DIR/issue-41110.rs:17:5: 17:9
+ // + span: $DIR/issue_41110.rs:17:5: 17:9
// + literal: Const { ty: fn(S) {std::mem::drop::<S>}, val: Value(<ZST>) }
}
bb1: {
- StorageDead(_4); // scope 2 at $DIR/issue-41110.rs:+3:11: +3:12
- StorageDead(_3); // scope 2 at $DIR/issue-41110.rs:+3:12: +3:13
- StorageLive(_5); // scope 2 at $DIR/issue-41110.rs:+4:9: +4:10
- _6 = const false; // scope 2 at $DIR/issue-41110.rs:+4:9: +4:10
- _5 = move _1; // scope 2 at $DIR/issue-41110.rs:+4:9: +4:10
- goto -> bb12; // scope 2 at $DIR/issue-41110.rs:+4:5: +4:6
+ StorageDead(_4); // scope 2 at $DIR/issue_41110.rs:+3:11: +3:12
+ StorageDead(_3); // scope 2 at $DIR/issue_41110.rs:+3:12: +3:13
+ StorageLive(_5); // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
+ _6 = const false; // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
+ _5 = move _1; // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
+ goto -> bb12; // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
}
bb2: {
- goto -> bb3; // scope 2 at $DIR/issue-41110.rs:+4:9: +4:10
+ goto -> bb3; // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
}
bb3: {
- StorageDead(_5); // scope 2 at $DIR/issue-41110.rs:+4:9: +4:10
- _0 = const (); // scope 0 at $DIR/issue-41110.rs:+0:15: +5:2
- drop(_2) -> [return: bb4, unwind: bb9]; // scope 1 at $DIR/issue-41110.rs:+5:1: +5:2
+ StorageDead(_5); // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
+ _0 = const (); // scope 0 at $DIR/issue_41110.rs:+0:15: +5:2
+ drop(_2) -> [return: bb4, unwind: bb9]; // scope 1 at $DIR/issue_41110.rs:+5:1: +5:2
}
bb4: {
- StorageDead(_2); // scope 1 at $DIR/issue-41110.rs:+5:1: +5:2
- goto -> bb5; // scope 0 at $DIR/issue-41110.rs:+5:1: +5:2
+ StorageDead(_2); // scope 1 at $DIR/issue_41110.rs:+5:1: +5:2
+ goto -> bb5; // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
}
bb5: {
- _6 = const false; // scope 0 at $DIR/issue-41110.rs:+5:1: +5:2
- StorageDead(_1); // scope 0 at $DIR/issue-41110.rs:+5:1: +5:2
- return; // scope 0 at $DIR/issue-41110.rs:+5:2: +5:2
+ _6 = const false; // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
+ StorageDead(_1); // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
+ return; // scope 0 at $DIR/issue_41110.rs:+5:2: +5:2
}
bb6 (cleanup): {
- goto -> bb8; // scope 2 at $DIR/issue-41110.rs:+4:9: +4:10
+ goto -> bb8; // scope 2 at $DIR/issue_41110.rs:+4:9: +4:10
}
bb7 (cleanup): {
- goto -> bb8; // scope 2 at $DIR/issue-41110.rs:+3:11: +3:12
+ goto -> bb8; // scope 2 at $DIR/issue_41110.rs:+3:11: +3:12
}
bb8 (cleanup): {
- goto -> bb9; // scope 1 at $DIR/issue-41110.rs:+5:1: +5:2
+ goto -> bb9; // scope 1 at $DIR/issue_41110.rs:+5:1: +5:2
}
bb9 (cleanup): {
- goto -> bb14; // scope 0 at $DIR/issue-41110.rs:+5:1: +5:2
+ goto -> bb14; // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
}
bb10 (cleanup): {
- resume; // scope 0 at $DIR/issue-41110.rs:+0:1: +5:2
+ resume; // scope 0 at $DIR/issue_41110.rs:+0:1: +5:2
}
bb11 (cleanup): {
- _2 = move _5; // scope 2 at $DIR/issue-41110.rs:+4:5: +4:6
- goto -> bb6; // scope 2 at $DIR/issue-41110.rs:+4:5: +4:6
+ _2 = move _5; // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
+ goto -> bb6; // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
}
bb12: {
- _2 = move _5; // scope 2 at $DIR/issue-41110.rs:+4:5: +4:6
- goto -> bb2; // scope 2 at $DIR/issue-41110.rs:+4:5: +4:6
+ _2 = move _5; // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
+ goto -> bb2; // scope 2 at $DIR/issue_41110.rs:+4:5: +4:6
}
bb13 (cleanup): {
- drop(_1) -> bb10; // scope 0 at $DIR/issue-41110.rs:+5:1: +5:2
+ drop(_1) -> bb10; // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
}
bb14 (cleanup): {
- switchInt(_6) -> [false: bb10, otherwise: bb13]; // scope 0 at $DIR/issue-41110.rs:+5:1: +5:2
+ switchInt(_6) -> [false: bb10, otherwise: bb13]; // scope 0 at $DIR/issue_41110.rs:+5:1: +5:2
}
}
--- /dev/null
+// Regression test for #41697. Using dump-mir was triggering
+// artificial cycles: during type-checking, we had to get the MIR for
+// the constant expressions in `[u8; 2]`, which in turn would trigger
+// an attempt to get the def-path, which in turn would request the
+// types of the impl, which would trigger a cycle. We suppressed this
+// cycle now by forcing mir-dump to avoid asking for types of an impl.
+
+#![feature(rustc_attrs)]
+
+use std::sync::Arc;
+
+trait Foo {
+ fn get(&self) -> [u8; 2];
+}
+
+
+// EMIT_MIR issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir
+impl Foo for [u8; 1+1] {
+ fn get(&self) -> [u8; 2] {
+ *self
+ }
+}
+
+struct Bar<T: ?Sized>(T);
+
+fn unsize_fat_ptr<'a>(x: &'a Bar<Foo + Send + 'a>) -> &'a Bar<Foo + 'a> {
+ x
+}
+
+fn unsize_nested_fat_ptr(x: Arc<Foo + Send>) -> Arc<Foo> {
+ x
+}
+
+fn main() {
+ let x: Box<Bar<Foo + Send>> = Box::new(Bar([1,2]));
+ assert_eq!(unsize_fat_ptr(&*x).0.get(), [1, 2]);
+
+ let x: Arc<Foo + Send> = Arc::new([3, 4]);
+ assert_eq!(unsize_nested_fat_ptr(x).get(), [3, 4]);
+}
-// MIR for `<impl at $DIR/issue-41697.rs:18:1: 18:23>::{constant#0}` after SimplifyCfg-promote-consts
+// MIR for `<impl at $DIR/issue_41697.rs:18:1: 18:23>::{constant#0}` after SimplifyCfg-promote-consts
-<impl at $DIR/issue-41697.rs:18:1: 18:23>::{constant#0}: usize = {
- let mut _0: usize; // return place in scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
- let mut _1: (usize, bool); // in scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
+<impl at $DIR/issue_41697.rs:18:1: 18:23>::{constant#0}: usize = {
+ let mut _0: usize; // return place in scope 0 at $DIR/issue_41697.rs:+0:19: +0:22
+ let mut _1: (usize, bool); // in scope 0 at $DIR/issue_41697.rs:+0:19: +0:22
bb0: {
- _1 = CheckedAdd(const 1_usize, const 1_usize); // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
- assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_usize, const 1_usize) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
+ _1 = CheckedAdd(const 1_usize, const 1_usize); // scope 0 at $DIR/issue_41697.rs:+0:19: +0:22
+ assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_usize, const 1_usize) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue_41697.rs:+0:19: +0:22
}
bb1: {
- _0 = move (_1.0: usize); // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
- return; // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
+ _0 = move (_1.0: usize); // scope 0 at $DIR/issue_41697.rs:+0:19: +0:22
+ return; // scope 0 at $DIR/issue_41697.rs:+0:19: +0:22
}
bb2 (cleanup): {
- resume; // scope 0 at $DIR/issue-41697.rs:+0:19: +0:22
+ resume; // scope 0 at $DIR/issue_41697.rs:+0:19: +0:22
}
}
// MIR for `main` after ElaborateDrops
fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/issue-41888.rs:+0:11: +0:11
- let _1: E; // in scope 0 at $DIR/issue-41888.rs:+1:9: +1:10
- let mut _2: bool; // in scope 0 at $DIR/issue-41888.rs:+2:8: +2:14
- let mut _3: E; // in scope 0 at $DIR/issue-41888.rs:+3:13: +3:20
- let mut _4: K; // in scope 0 at $DIR/issue-41888.rs:+3:18: +3:19
- let mut _5: isize; // in scope 0 at $DIR/issue-41888.rs:+4:16: +4:24
- let mut _7: bool; // in scope 0 at $DIR/issue-41888.rs:+9:1: +9:2
- let mut _8: bool; // in scope 0 at $DIR/issue-41888.rs:+9:1: +9:2
- let mut _9: bool; // in scope 0 at $DIR/issue-41888.rs:+9:1: +9:2
- let mut _10: isize; // in scope 0 at $DIR/issue-41888.rs:+9:1: +9:2
- let mut _11: isize; // in scope 0 at $DIR/issue-41888.rs:+9:1: +9:2
+ let mut _0: (); // return place in scope 0 at $DIR/issue_41888.rs:+0:11: +0:11
+ let _1: E; // in scope 0 at $DIR/issue_41888.rs:+1:9: +1:10
+ let mut _2: bool; // in scope 0 at $DIR/issue_41888.rs:+2:8: +2:14
+ let mut _3: E; // in scope 0 at $DIR/issue_41888.rs:+3:13: +3:20
+ let mut _4: K; // in scope 0 at $DIR/issue_41888.rs:+3:18: +3:19
+ let mut _5: isize; // in scope 0 at $DIR/issue_41888.rs:+4:16: +4:24
+ let mut _7: bool; // in scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
+ let mut _8: bool; // in scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
+ let mut _9: bool; // in scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
+ let mut _10: isize; // in scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
+ let mut _11: isize; // in scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
scope 1 {
- debug e => _1; // in scope 1 at $DIR/issue-41888.rs:+1:9: +1:10
+ debug e => _1; // in scope 1 at $DIR/issue_41888.rs:+1:9: +1:10
scope 2 {
- debug _k => _6; // in scope 2 at $DIR/issue-41888.rs:+4:21: +4:23
- let _6: K; // in scope 2 at $DIR/issue-41888.rs:+4:21: +4:23
+ debug _k => _6; // in scope 2 at $DIR/issue_41888.rs:+4:21: +4:23
+ let _6: K; // in scope 2 at $DIR/issue_41888.rs:+4:21: +4:23
}
}
bb0: {
- _9 = const false; // scope 0 at $DIR/issue-41888.rs:+1:9: +1:10
- _7 = const false; // scope 0 at $DIR/issue-41888.rs:+1:9: +1:10
- _8 = const false; // scope 0 at $DIR/issue-41888.rs:+1:9: +1:10
- StorageLive(_1); // scope 0 at $DIR/issue-41888.rs:+1:9: +1:10
- StorageLive(_2); // scope 1 at $DIR/issue-41888.rs:+2:8: +2:14
- _2 = cond() -> [return: bb1, unwind: bb11]; // scope 1 at $DIR/issue-41888.rs:+2:8: +2:14
+ _9 = const false; // scope 0 at $DIR/issue_41888.rs:+1:9: +1:10
+ _7 = const false; // scope 0 at $DIR/issue_41888.rs:+1:9: +1:10
+ _8 = const false; // scope 0 at $DIR/issue_41888.rs:+1:9: +1:10
+ StorageLive(_1); // scope 0 at $DIR/issue_41888.rs:+1:9: +1:10
+ StorageLive(_2); // scope 1 at $DIR/issue_41888.rs:+2:8: +2:14
+ _2 = cond() -> [return: bb1, unwind: bb11]; // scope 1 at $DIR/issue_41888.rs:+2:8: +2:14
// mir::Constant
- // + span: $DIR/issue-41888.rs:8:8: 8:12
+ // + span: $DIR/issue_41888.rs:8:8: 8:12
// + literal: Const { ty: fn() -> bool {cond}, val: Value(<ZST>) }
}
bb1: {
- switchInt(move _2) -> [false: bb7, otherwise: bb2]; // scope 1 at $DIR/issue-41888.rs:+2:8: +2:14
+ switchInt(move _2) -> [false: bb7, otherwise: bb2]; // scope 1 at $DIR/issue_41888.rs:+2:8: +2:14
}
bb2: {
- StorageLive(_3); // scope 1 at $DIR/issue-41888.rs:+3:13: +3:20
- StorageLive(_4); // scope 1 at $DIR/issue-41888.rs:+3:18: +3:19
- _4 = K; // scope 1 at $DIR/issue-41888.rs:+3:18: +3:19
- _3 = E::F(move _4); // scope 1 at $DIR/issue-41888.rs:+3:13: +3:20
- StorageDead(_4); // scope 1 at $DIR/issue-41888.rs:+3:19: +3:20
- goto -> bb14; // scope 1 at $DIR/issue-41888.rs:+3:9: +3:10
+ StorageLive(_3); // scope 1 at $DIR/issue_41888.rs:+3:13: +3:20
+ StorageLive(_4); // scope 1 at $DIR/issue_41888.rs:+3:18: +3:19
+ _4 = K; // scope 1 at $DIR/issue_41888.rs:+3:18: +3:19
+ _3 = E::F(move _4); // scope 1 at $DIR/issue_41888.rs:+3:13: +3:20
+ StorageDead(_4); // scope 1 at $DIR/issue_41888.rs:+3:19: +3:20
+ goto -> bb14; // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
}
bb3: {
- goto -> bb4; // scope 1 at $DIR/issue-41888.rs:+3:19: +3:20
+ goto -> bb4; // scope 1 at $DIR/issue_41888.rs:+3:19: +3:20
}
bb4: {
- StorageDead(_3); // scope 1 at $DIR/issue-41888.rs:+3:19: +3:20
- _5 = discriminant(_1); // scope 2 at $DIR/issue-41888.rs:+4:16: +4:24
- switchInt(move _5) -> [0_isize: bb5, otherwise: bb6]; // scope 2 at $DIR/issue-41888.rs:+4:16: +4:24
+ StorageDead(_3); // scope 1 at $DIR/issue_41888.rs:+3:19: +3:20
+ _5 = discriminant(_1); // scope 2 at $DIR/issue_41888.rs:+4:16: +4:24
+ switchInt(move _5) -> [0_isize: bb5, otherwise: bb6]; // scope 2 at $DIR/issue_41888.rs:+4:16: +4:24
}
bb5: {
- StorageLive(_6); // scope 2 at $DIR/issue-41888.rs:+4:21: +4:23
- _9 = const false; // scope 2 at $DIR/issue-41888.rs:+4:21: +4:23
- _6 = move ((_1 as F).0: K); // scope 2 at $DIR/issue-41888.rs:+4:21: +4:23
- _0 = const (); // scope 2 at $DIR/issue-41888.rs:+4:29: +7:10
- StorageDead(_6); // scope 1 at $DIR/issue-41888.rs:+7:9: +7:10
- goto -> bb8; // scope 1 at $DIR/issue-41888.rs:+4:9: +7:10
+ StorageLive(_6); // scope 2 at $DIR/issue_41888.rs:+4:21: +4:23
+ _9 = const false; // scope 2 at $DIR/issue_41888.rs:+4:21: +4:23
+ _6 = move ((_1 as F).0: K); // scope 2 at $DIR/issue_41888.rs:+4:21: +4:23
+ _0 = const (); // scope 2 at $DIR/issue_41888.rs:+4:29: +7:10
+ StorageDead(_6); // scope 1 at $DIR/issue_41888.rs:+7:9: +7:10
+ goto -> bb8; // scope 1 at $DIR/issue_41888.rs:+4:9: +7:10
}
bb6: {
- _0 = const (); // scope 1 at $DIR/issue-41888.rs:+7:10: +7:10
- goto -> bb8; // scope 1 at $DIR/issue-41888.rs:+4:9: +7:10
+ _0 = const (); // scope 1 at $DIR/issue_41888.rs:+7:10: +7:10
+ goto -> bb8; // scope 1 at $DIR/issue_41888.rs:+4:9: +7:10
}
bb7: {
- _0 = const (); // scope 1 at $DIR/issue-41888.rs:+8:6: +8:6
- goto -> bb8; // scope 1 at $DIR/issue-41888.rs:+2:5: +8:6
+ _0 = const (); // scope 1 at $DIR/issue_41888.rs:+8:6: +8:6
+ goto -> bb8; // scope 1 at $DIR/issue_41888.rs:+2:5: +8:6
}
bb8: {
- StorageDead(_2); // scope 1 at $DIR/issue-41888.rs:+8:5: +8:6
- goto -> bb20; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2
+ StorageDead(_2); // scope 1 at $DIR/issue_41888.rs:+8:5: +8:6
+ goto -> bb20; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
}
bb9: {
- _7 = const false; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2
- _8 = const false; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2
- _9 = const false; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2
- StorageDead(_1); // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2
- return; // scope 0 at $DIR/issue-41888.rs:+9:2: +9:2
+ _7 = const false; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
+ _8 = const false; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
+ _9 = const false; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
+ StorageDead(_1); // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
+ return; // scope 0 at $DIR/issue_41888.rs:+9:2: +9:2
}
bb10 (cleanup): {
- goto -> bb11; // scope 1 at $DIR/issue-41888.rs:+3:19: +3:20
+ goto -> bb11; // scope 1 at $DIR/issue_41888.rs:+3:19: +3:20
}
bb11 (cleanup): {
- goto -> bb12; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2
+ goto -> bb12; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
}
bb12 (cleanup): {
- resume; // scope 0 at $DIR/issue-41888.rs:+0:1: +9:2
+ resume; // scope 0 at $DIR/issue_41888.rs:+0:1: +9:2
}
bb13 (cleanup): {
- _7 = const true; // scope 1 at $DIR/issue-41888.rs:+3:9: +3:10
- _8 = const true; // scope 1 at $DIR/issue-41888.rs:+3:9: +3:10
- _9 = const true; // scope 1 at $DIR/issue-41888.rs:+3:9: +3:10
- _1 = move _3; // scope 1 at $DIR/issue-41888.rs:+3:9: +3:10
- goto -> bb10; // scope 1 at $DIR/issue-41888.rs:+3:9: +3:10
+ _7 = const true; // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
+ _8 = const true; // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
+ _9 = const true; // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
+ _1 = move _3; // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
+ goto -> bb10; // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
}
bb14: {
- _7 = const true; // scope 1 at $DIR/issue-41888.rs:+3:9: +3:10
- _8 = const true; // scope 1 at $DIR/issue-41888.rs:+3:9: +3:10
- _9 = const true; // scope 1 at $DIR/issue-41888.rs:+3:9: +3:10
- _1 = move _3; // scope 1 at $DIR/issue-41888.rs:+3:9: +3:10
- goto -> bb3; // scope 1 at $DIR/issue-41888.rs:+3:9: +3:10
+ _7 = const true; // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
+ _8 = const true; // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
+ _9 = const true; // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
+ _1 = move _3; // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
+ goto -> bb3; // scope 1 at $DIR/issue_41888.rs:+3:9: +3:10
}
bb15: {
- _7 = const false; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2
- goto -> bb9; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2
+ _7 = const false; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
+ goto -> bb9; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
}
bb16 (cleanup): {
- goto -> bb12; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2
+ goto -> bb12; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
}
bb17: {
- drop(_1) -> [return: bb15, unwind: bb12]; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2
+ drop(_1) -> [return: bb15, unwind: bb12]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
}
bb18 (cleanup): {
- drop(_1) -> bb12; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2
+ drop(_1) -> bb12; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
}
bb19: {
- _10 = discriminant(_1); // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2
- switchInt(move _10) -> [0_isize: bb15, otherwise: bb17]; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2
+ _10 = discriminant(_1); // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
+ switchInt(move _10) -> [0_isize: bb15, otherwise: bb17]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
}
bb20: {
- switchInt(_7) -> [false: bb15, otherwise: bb19]; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2
+ switchInt(_7) -> [false: bb15, otherwise: bb19]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
}
bb21 (cleanup): {
- _11 = discriminant(_1); // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2
- switchInt(move _11) -> [0_isize: bb16, otherwise: bb18]; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2
+ _11 = discriminant(_1); // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
+ switchInt(move _11) -> [0_isize: bb16, otherwise: bb18]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
}
bb22 (cleanup): {
- switchInt(_7) -> [false: bb12, otherwise: bb21]; // scope 0 at $DIR/issue-41888.rs:+9:1: +9:2
+ switchInt(_7) -> [false: bb12, otherwise: bb21]; // scope 0 at $DIR/issue_41888.rs:+9:1: +9:2
}
}
--- /dev/null
+// ignore-wasm32-bare compiled with panic=abort by default
+// check that we clear the "ADT master drop flag" even when there are
+// no fields to be dropped.
+
+// EMIT_MIR issue_41888.main.ElaborateDrops.after.mir
+fn main() {
+ let e;
+ if cond() {
+ e = E::F(K);
+ if let E::F(_k) = e {
+ // older versions of rustc used to not clear the
+ // drop flag for `e` in this path.
+ }
+ }
+}
+
+fn cond() -> bool { false }
+
+struct K;
+
+enum E {
+ F(K),
+ G(Box<E>)
+}
+++ /dev/null
-// MIR for `main` 0 mir_map
-
-fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/issue-49232.rs:+0:11: +0:11
- let mut _1: (); // in scope 0 at $DIR/issue-49232.rs:+0:1: +10:2
- let _2: i32; // in scope 0 at $DIR/issue-49232.rs:+2:13: +2:19
- let mut _3: bool; // in scope 0 at $DIR/issue-49232.rs:+3:19: +3:23
- let mut _4: !; // in scope 0 at $DIR/issue-49232.rs:+5:25: +5:30
- let _5: (); // in scope 0 at $DIR/issue-49232.rs:+8:9: +8:22
- let mut _6: &i32; // in scope 0 at $DIR/issue-49232.rs:+8:14: +8:21
- scope 1 {
- debug beacon => _2; // in scope 1 at $DIR/issue-49232.rs:+2:13: +2:19
- }
-
- bb0: {
- goto -> bb1; // scope 0 at $DIR/issue-49232.rs:+1:5: +9:6
- }
-
- bb1: {
- falseUnwind -> [real: bb2, cleanup: bb11]; // scope 0 at $DIR/issue-49232.rs:+1:5: +9:6
- }
-
- bb2: {
- StorageLive(_2); // scope 0 at $DIR/issue-49232.rs:+2:13: +2:19
- StorageLive(_3); // scope 0 at $DIR/issue-49232.rs:+3:19: +3:23
- _3 = const true; // scope 0 at $DIR/issue-49232.rs:+3:19: +3:23
- FakeRead(ForMatchedPlace(None), _3); // scope 0 at $DIR/issue-49232.rs:+3:19: +3:23
- switchInt(_3) -> [false: bb3, otherwise: bb4]; // scope 0 at $DIR/issue-49232.rs:+3:13: +3:23
- }
-
- bb3: {
- falseEdge -> [real: bb5, imaginary: bb4]; // scope 0 at $DIR/issue-49232.rs:+4:17: +4:22
- }
-
- bb4: {
- _0 = const (); // scope 0 at $DIR/issue-49232.rs:+5:25: +5:30
- goto -> bb10; // scope 0 at $DIR/issue-49232.rs:+5:25: +5:30
- }
-
- bb5: {
- _2 = const 4_i32; // scope 0 at $DIR/issue-49232.rs:+4:26: +4:27
- goto -> bb8; // scope 0 at $DIR/issue-49232.rs:+4:26: +4:27
- }
-
- bb6: {
- unreachable; // scope 0 at $DIR/issue-49232.rs:+5:25: +5:30
- }
-
- bb7: {
- goto -> bb8; // scope 0 at $DIR/issue-49232.rs:+6:13: +6:14
- }
-
- bb8: {
- FakeRead(ForLet(None), _2); // scope 0 at $DIR/issue-49232.rs:+2:13: +2:19
- StorageDead(_3); // scope 0 at $DIR/issue-49232.rs:+7:10: +7:11
- StorageLive(_5); // scope 1 at $DIR/issue-49232.rs:+8:9: +8:22
- StorageLive(_6); // scope 1 at $DIR/issue-49232.rs:+8:14: +8:21
- _6 = &_2; // scope 1 at $DIR/issue-49232.rs:+8:14: +8:21
- _5 = std::mem::drop::<&i32>(move _6) -> [return: bb9, unwind: bb11]; // scope 1 at $DIR/issue-49232.rs:+8:9: +8:22
- // mir::Constant
- // + span: $DIR/issue-49232.rs:13:9: 13:13
- // + literal: Const { ty: fn(&i32) {std::mem::drop::<&i32>}, val: Value(<ZST>) }
- }
-
- bb9: {
- StorageDead(_6); // scope 1 at $DIR/issue-49232.rs:+8:21: +8:22
- StorageDead(_5); // scope 1 at $DIR/issue-49232.rs:+8:22: +8:23
- _1 = const (); // scope 0 at $DIR/issue-49232.rs:+1:10: +9:6
- StorageDead(_2); // scope 0 at $DIR/issue-49232.rs:+9:5: +9:6
- goto -> bb1; // scope 0 at $DIR/issue-49232.rs:+1:5: +9:6
- }
-
- bb10: {
- StorageDead(_3); // scope 0 at $DIR/issue-49232.rs:+7:10: +7:11
- StorageDead(_2); // scope 0 at $DIR/issue-49232.rs:+9:5: +9:6
- return; // scope 0 at $DIR/issue-49232.rs:+10:2: +10:2
- }
-
- bb11 (cleanup): {
- resume; // scope 0 at $DIR/issue-49232.rs:+0:1: +10:2
- }
-}
--- /dev/null
+// check that we don't forget to drop the Box if we early return before
+// initializing it
+// ignore-wasm32-bare compiled with panic=abort by default
+
+#![feature(box_syntax)]
+
+// EMIT_MIR issue_62289.test.ElaborateDrops.before.mir
+fn test() -> Option<Box<u32>> {
+ Some(box (None?))
+}
+
+fn main() {
+ test();
+}
// MIR for `test` before ElaborateDrops
fn test() -> Option<Box<u32>> {
- let mut _0: std::option::Option<std::boxed::Box<u32>>; // return place in scope 0 at $DIR/issue-62289.rs:+0:14: +0:30
- let mut _1: std::boxed::Box<u32>; // in scope 0 at $DIR/issue-62289.rs:+1:10: +1:21
- let mut _2: usize; // in scope 0 at $DIR/issue-62289.rs:+1:10: +1:21
- let mut _3: usize; // in scope 0 at $DIR/issue-62289.rs:+1:10: +1:21
- let mut _4: *mut u8; // in scope 0 at $DIR/issue-62289.rs:+1:10: +1:21
- let mut _5: std::boxed::Box<u32>; // in scope 0 at $DIR/issue-62289.rs:+1:10: +1:21
- let mut _6: std::ops::ControlFlow<std::option::Option<std::convert::Infallible>, u32>; // in scope 0 at $DIR/issue-62289.rs:+1:15: +1:20
- let mut _7: std::option::Option<u32>; // in scope 0 at $DIR/issue-62289.rs:+1:15: +1:19
- let mut _8: isize; // in scope 0 at $DIR/issue-62289.rs:+1:19: +1:20
- let _9: std::option::Option<std::convert::Infallible>; // in scope 0 at $DIR/issue-62289.rs:+1:19: +1:20
- let mut _10: !; // in scope 0 at $DIR/issue-62289.rs:+1:19: +1:20
- let mut _11: std::option::Option<std::convert::Infallible>; // in scope 0 at $DIR/issue-62289.rs:+1:19: +1:20
- let _12: u32; // in scope 0 at $DIR/issue-62289.rs:+1:15: +1:20
+ let mut _0: std::option::Option<std::boxed::Box<u32>>; // return place in scope 0 at $DIR/issue_62289.rs:+0:14: +0:30
+ let mut _1: std::boxed::Box<u32>; // in scope 0 at $DIR/issue_62289.rs:+1:10: +1:21
+ let mut _2: usize; // in scope 0 at $DIR/issue_62289.rs:+1:10: +1:21
+ let mut _3: usize; // in scope 0 at $DIR/issue_62289.rs:+1:10: +1:21
+ let mut _4: *mut u8; // in scope 0 at $DIR/issue_62289.rs:+1:10: +1:21
+ let mut _5: std::boxed::Box<u32>; // in scope 0 at $DIR/issue_62289.rs:+1:10: +1:21
+ let mut _6: std::ops::ControlFlow<std::option::Option<std::convert::Infallible>, u32>; // in scope 0 at $DIR/issue_62289.rs:+1:15: +1:20
+ let mut _7: std::option::Option<u32>; // in scope 0 at $DIR/issue_62289.rs:+1:15: +1:19
+ let mut _8: isize; // in scope 0 at $DIR/issue_62289.rs:+1:19: +1:20
+ let _9: std::option::Option<std::convert::Infallible>; // in scope 0 at $DIR/issue_62289.rs:+1:19: +1:20
+ let mut _10: !; // in scope 0 at $DIR/issue_62289.rs:+1:19: +1:20
+ let mut _11: std::option::Option<std::convert::Infallible>; // in scope 0 at $DIR/issue_62289.rs:+1:19: +1:20
+ let _12: u32; // in scope 0 at $DIR/issue_62289.rs:+1:15: +1:20
scope 1 {
}
scope 2 {
- debug residual => _9; // in scope 2 at $DIR/issue-62289.rs:+1:19: +1:20
+ debug residual => _9; // in scope 2 at $DIR/issue_62289.rs:+1:19: +1:20
scope 3 {
}
}
scope 4 {
- debug val => _12; // in scope 4 at $DIR/issue-62289.rs:+1:15: +1:20
+ debug val => _12; // in scope 4 at $DIR/issue_62289.rs:+1:15: +1:20
scope 5 {
}
}
bb0: {
- StorageLive(_1); // scope 0 at $DIR/issue-62289.rs:+1:10: +1:21
- _2 = SizeOf(u32); // scope 1 at $DIR/issue-62289.rs:+1:10: +1:21
- _3 = AlignOf(u32); // scope 1 at $DIR/issue-62289.rs:+1:10: +1:21
- _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 1 at $DIR/issue-62289.rs:+1:10: +1:21
+ StorageLive(_1); // scope 0 at $DIR/issue_62289.rs:+1:10: +1:21
+ _2 = SizeOf(u32); // scope 1 at $DIR/issue_62289.rs:+1:10: +1:21
+ _3 = AlignOf(u32); // scope 1 at $DIR/issue_62289.rs:+1:10: +1:21
+ _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 1 at $DIR/issue_62289.rs:+1:10: +1:21
// mir::Constant
- // + span: $DIR/issue-62289.rs:9:10: 9:21
+ // + span: $DIR/issue_62289.rs:9:10: 9:21
// + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
}
bb1: {
- StorageLive(_5); // scope 0 at $DIR/issue-62289.rs:+1:10: +1:21
- _5 = ShallowInitBox(move _4, u32); // scope 0 at $DIR/issue-62289.rs:+1:10: +1:21
- StorageLive(_6); // scope 0 at $DIR/issue-62289.rs:+1:15: +1:20
- StorageLive(_7); // scope 0 at $DIR/issue-62289.rs:+1:15: +1:19
- _7 = Option::<u32>::None; // scope 0 at $DIR/issue-62289.rs:+1:15: +1:19
- _6 = <Option<u32> as Try>::branch(move _7) -> [return: bb2, unwind: bb12]; // scope 0 at $DIR/issue-62289.rs:+1:15: +1:20
+ StorageLive(_5); // scope 0 at $DIR/issue_62289.rs:+1:10: +1:21
+ _5 = ShallowInitBox(move _4, u32); // scope 0 at $DIR/issue_62289.rs:+1:10: +1:21
+ StorageLive(_6); // scope 0 at $DIR/issue_62289.rs:+1:15: +1:20
+ StorageLive(_7); // scope 0 at $DIR/issue_62289.rs:+1:15: +1:19
+ _7 = Option::<u32>::None; // scope 0 at $DIR/issue_62289.rs:+1:15: +1:19
+ _6 = <Option<u32> as Try>::branch(move _7) -> [return: bb2, unwind: bb12]; // scope 0 at $DIR/issue_62289.rs:+1:15: +1:20
// mir::Constant
- // + span: $DIR/issue-62289.rs:9:15: 9:20
+ // + span: $DIR/issue_62289.rs:9:15: 9:20
// + literal: Const { ty: fn(Option<u32>) -> ControlFlow<<Option<u32> as Try>::Residual, <Option<u32> as Try>::Output> {<Option<u32> as Try>::branch}, val: Value(<ZST>) }
}
bb2: {
- StorageDead(_7); // scope 0 at $DIR/issue-62289.rs:+1:19: +1:20
- _8 = discriminant(_6); // scope 0 at $DIR/issue-62289.rs:+1:15: +1:20
- switchInt(move _8) -> [0_isize: bb3, 1_isize: bb5, otherwise: bb4]; // scope 0 at $DIR/issue-62289.rs:+1:15: +1:20
+ StorageDead(_7); // scope 0 at $DIR/issue_62289.rs:+1:19: +1:20
+ _8 = discriminant(_6); // scope 0 at $DIR/issue_62289.rs:+1:15: +1:20
+ switchInt(move _8) -> [0_isize: bb3, 1_isize: bb5, otherwise: bb4]; // scope 0 at $DIR/issue_62289.rs:+1:15: +1:20
}
bb3: {
- StorageLive(_12); // scope 0 at $DIR/issue-62289.rs:+1:15: +1:20
- _12 = ((_6 as Continue).0: u32); // scope 0 at $DIR/issue-62289.rs:+1:15: +1:20
- (*_5) = _12; // scope 5 at $DIR/issue-62289.rs:+1:15: +1:20
- StorageDead(_12); // scope 0 at $DIR/issue-62289.rs:+1:19: +1:20
- _1 = move _5; // scope 0 at $DIR/issue-62289.rs:+1:10: +1:21
- drop(_5) -> [return: bb7, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:+1:20: +1:21
+ StorageLive(_12); // scope 0 at $DIR/issue_62289.rs:+1:15: +1:20
+ _12 = ((_6 as Continue).0: u32); // scope 0 at $DIR/issue_62289.rs:+1:15: +1:20
+ (*_5) = _12; // scope 5 at $DIR/issue_62289.rs:+1:15: +1:20
+ StorageDead(_12); // scope 0 at $DIR/issue_62289.rs:+1:19: +1:20
+ _1 = move _5; // scope 0 at $DIR/issue_62289.rs:+1:10: +1:21
+ drop(_5) -> [return: bb7, unwind: bb11]; // scope 0 at $DIR/issue_62289.rs:+1:20: +1:21
}
bb4: {
- unreachable; // scope 0 at $DIR/issue-62289.rs:+1:15: +1:20
+ unreachable; // scope 0 at $DIR/issue_62289.rs:+1:15: +1:20
}
bb5: {
- StorageLive(_9); // scope 0 at $DIR/issue-62289.rs:+1:19: +1:20
- _9 = ((_6 as Break).0: std::option::Option<std::convert::Infallible>); // scope 0 at $DIR/issue-62289.rs:+1:19: +1:20
- StorageLive(_11); // scope 3 at $DIR/issue-62289.rs:+1:19: +1:20
- _11 = _9; // scope 3 at $DIR/issue-62289.rs:+1:19: +1:20
- _0 = <Option<Box<u32>> as FromResidual<Option<Infallible>>>::from_residual(move _11) -> [return: bb6, unwind: bb12]; // scope 3 at $DIR/issue-62289.rs:+1:15: +1:20
+ StorageLive(_9); // scope 0 at $DIR/issue_62289.rs:+1:19: +1:20
+ _9 = ((_6 as Break).0: std::option::Option<std::convert::Infallible>); // scope 0 at $DIR/issue_62289.rs:+1:19: +1:20
+ StorageLive(_11); // scope 3 at $DIR/issue_62289.rs:+1:19: +1:20
+ _11 = _9; // scope 3 at $DIR/issue_62289.rs:+1:19: +1:20
+ _0 = <Option<Box<u32>> as FromResidual<Option<Infallible>>>::from_residual(move _11) -> [return: bb6, unwind: bb12]; // scope 3 at $DIR/issue_62289.rs:+1:15: +1:20
// mir::Constant
- // + span: $DIR/issue-62289.rs:9:19: 9:20
+ // + span: $DIR/issue_62289.rs:9:19: 9:20
// + literal: Const { ty: fn(Option<Infallible>) -> Option<Box<u32>> {<Option<Box<u32>> as FromResidual<Option<Infallible>>>::from_residual}, val: Value(<ZST>) }
}
bb6: {
- StorageDead(_11); // scope 3 at $DIR/issue-62289.rs:+1:19: +1:20
- StorageDead(_9); // scope 0 at $DIR/issue-62289.rs:+1:19: +1:20
- drop(_5) -> bb9; // scope 0 at $DIR/issue-62289.rs:+1:20: +1:21
+ StorageDead(_11); // scope 3 at $DIR/issue_62289.rs:+1:19: +1:20
+ StorageDead(_9); // scope 0 at $DIR/issue_62289.rs:+1:19: +1:20
+ drop(_5) -> bb9; // scope 0 at $DIR/issue_62289.rs:+1:20: +1:21
}
bb7: {
- StorageDead(_5); // scope 0 at $DIR/issue-62289.rs:+1:20: +1:21
- _0 = Option::<Box<u32>>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:+1:5: +1:22
- drop(_1) -> bb8; // scope 0 at $DIR/issue-62289.rs:+1:21: +1:22
+ StorageDead(_5); // scope 0 at $DIR/issue_62289.rs:+1:20: +1:21
+ _0 = Option::<Box<u32>>::Some(move _1); // scope 0 at $DIR/issue_62289.rs:+1:5: +1:22
+ drop(_1) -> bb8; // scope 0 at $DIR/issue_62289.rs:+1:21: +1:22
}
bb8: {
- StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:+1:21: +1:22
- StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:+2:1: +2:2
- goto -> bb10; // scope 0 at $DIR/issue-62289.rs:+2:2: +2:2
+ StorageDead(_1); // scope 0 at $DIR/issue_62289.rs:+1:21: +1:22
+ StorageDead(_6); // scope 0 at $DIR/issue_62289.rs:+2:1: +2:2
+ goto -> bb10; // scope 0 at $DIR/issue_62289.rs:+2:2: +2:2
}
bb9: {
- StorageDead(_5); // scope 0 at $DIR/issue-62289.rs:+1:20: +1:21
- StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:+1:21: +1:22
- StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:+2:1: +2:2
- goto -> bb10; // scope 0 at $DIR/issue-62289.rs:+2:2: +2:2
+ StorageDead(_5); // scope 0 at $DIR/issue_62289.rs:+1:20: +1:21
+ StorageDead(_1); // scope 0 at $DIR/issue_62289.rs:+1:21: +1:22
+ StorageDead(_6); // scope 0 at $DIR/issue_62289.rs:+2:1: +2:2
+ goto -> bb10; // scope 0 at $DIR/issue_62289.rs:+2:2: +2:2
}
bb10: {
- return; // scope 0 at $DIR/issue-62289.rs:+2:2: +2:2
+ return; // scope 0 at $DIR/issue_62289.rs:+2:2: +2:2
}
bb11 (cleanup): {
- drop(_1) -> bb13; // scope 0 at $DIR/issue-62289.rs:+1:21: +1:22
+ drop(_1) -> bb13; // scope 0 at $DIR/issue_62289.rs:+1:21: +1:22
}
bb12 (cleanup): {
- drop(_5) -> bb13; // scope 0 at $DIR/issue-62289.rs:+1:20: +1:21
+ drop(_5) -> bb13; // scope 0 at $DIR/issue_62289.rs:+1:20: +1:21
}
bb13 (cleanup): {
- resume; // scope 0 at $DIR/issue-62289.rs:+0:1: +2:2
+ resume; // scope 0 at $DIR/issue_62289.rs:+0:1: +2:2
}
}
--- /dev/null
+// MIR for `bar` after built
+
+fn bar(_1: [(Never, u32); 1]) -> u32 {
+ let mut _0: u32; // return place in scope 0 at $DIR/issue_72181.rs:+0:40: +0:43
+ let _2: u32; // in scope 0 at $DIR/issue_72181.rs:+0:13: +0:14
+ scope 1 {
+ debug x => _2; // in scope 1 at $DIR/issue_72181.rs:+0:13: +0:14
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/issue_72181.rs:+0:13: +0:14
+ _2 = (_1[0 of 1].1: u32); // scope 0 at $DIR/issue_72181.rs:+0:13: +0:14
+ _0 = _2; // scope 1 at $DIR/issue_72181.rs:+0:46: +0:47
+ StorageDead(_2); // scope 0 at $DIR/issue_72181.rs:+0:48: +0:49
+ return; // scope 0 at $DIR/issue_72181.rs:+0:49: +0:49
+ }
+}
+++ /dev/null
-// MIR for `bar` 0 mir_map
-
-fn bar(_1: [(Never, u32); 1]) -> u32 {
- let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:+0:40: +0:43
- let _2: u32; // in scope 0 at $DIR/issue-72181.rs:+0:13: +0:14
- scope 1 {
- debug x => _2; // in scope 1 at $DIR/issue-72181.rs:+0:13: +0:14
- }
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:+0:13: +0:14
- _2 = (_1[0 of 1].1: u32); // scope 0 at $DIR/issue-72181.rs:+0:13: +0:14
- _0 = _2; // scope 1 at $DIR/issue-72181.rs:+0:46: +0:47
- StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:+0:48: +0:49
- return; // scope 0 at $DIR/issue-72181.rs:+0:49: +0:49
- }
-}
--- /dev/null
+// MIR for `foo` after built
+
+fn foo(_1: [(Never, u32); 1]) -> u32 {
+ debug xs => _1; // in scope 0 at $DIR/issue_72181.rs:+0:8: +0:10
+ let mut _0: u32; // return place in scope 0 at $DIR/issue_72181.rs:+0:34: +0:37
+ let _2: usize; // in scope 0 at $DIR/issue_72181.rs:+0:43: +0:44
+ let mut _3: usize; // in scope 0 at $DIR/issue_72181.rs:+0:40: +0:45
+ let mut _4: bool; // in scope 0 at $DIR/issue_72181.rs:+0:40: +0:45
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/issue_72181.rs:+0:43: +0:44
+ _2 = const 0_usize; // scope 0 at $DIR/issue_72181.rs:+0:43: +0:44
+ _3 = Len(_1); // scope 0 at $DIR/issue_72181.rs:+0:40: +0:45
+ _4 = Lt(_2, _3); // scope 0 at $DIR/issue_72181.rs:+0:40: +0:45
+ assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, _2) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue_72181.rs:+0:40: +0:45
+ }
+
+ bb1: {
+ _0 = (_1[_2].1: u32); // scope 0 at $DIR/issue_72181.rs:+0:40: +0:47
+ StorageDead(_2); // scope 0 at $DIR/issue_72181.rs:+0:48: +0:49
+ return; // scope 0 at $DIR/issue_72181.rs:+0:49: +0:49
+ }
+
+ bb2 (cleanup): {
+ resume; // scope 0 at $DIR/issue_72181.rs:+0:1: +0:49
+ }
+}
+++ /dev/null
-// MIR for `foo` 0 mir_map
-
-fn foo(_1: [(Never, u32); 1]) -> u32 {
- debug xs => _1; // in scope 0 at $DIR/issue-72181.rs:+0:8: +0:10
- let mut _0: u32; // return place in scope 0 at $DIR/issue-72181.rs:+0:34: +0:37
- let _2: usize; // in scope 0 at $DIR/issue-72181.rs:+0:43: +0:44
- let mut _3: usize; // in scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
- let mut _4: bool; // in scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/issue-72181.rs:+0:43: +0:44
- _2 = const 0_usize; // scope 0 at $DIR/issue-72181.rs:+0:43: +0:44
- _3 = Len(_1); // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
- _4 = Lt(_2, _3); // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
- assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, _2) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-72181.rs:+0:40: +0:45
- }
-
- bb1: {
- _0 = (_1[_2].1: u32); // scope 0 at $DIR/issue-72181.rs:+0:40: +0:47
- StorageDead(_2); // scope 0 at $DIR/issue-72181.rs:+0:48: +0:49
- return; // scope 0 at $DIR/issue-72181.rs:+0:49: +0:49
- }
-
- bb2 (cleanup): {
- resume; // scope 0 at $DIR/issue-72181.rs:+0:1: +0:49
- }
-}
--- /dev/null
+// MIR for `main` after built
+
+fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/issue_72181.rs:+0:11: +0:11
+ let mut _1: usize; // in scope 0 at $DIR/issue_72181.rs:+1:13: +1:34
+ let mut _3: Foo; // in scope 0 at $DIR/issue_72181.rs:+3:14: +3:27
+ let mut _4: Foo; // in scope 0 at $DIR/issue_72181.rs:+3:29: +3:42
+ let mut _5: u64; // in scope 0 at $DIR/issue_72181.rs:+4:13: +4:30
+ let _6: usize; // in scope 0 at $DIR/issue_72181.rs:+4:24: +4:25
+ let mut _7: usize; // in scope 0 at $DIR/issue_72181.rs:+4:22: +4:26
+ let mut _8: bool; // in scope 0 at $DIR/issue_72181.rs:+4:22: +4:26
+ scope 1 {
+ let _2: [Foo; 2]; // in scope 1 at $DIR/issue_72181.rs:+3:9: +3:10
+ scope 2 {
+ debug f => _2; // in scope 2 at $DIR/issue_72181.rs:+3:9: +3:10
+ scope 3 {
+ }
+ scope 4 {
+ }
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/issue_72181.rs:+1:13: +1:34
+ _1 = std::mem::size_of::<Foo>() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue_72181.rs:+1:13: +1:34
+ // mir::Constant
+ // + span: $DIR/issue_72181.rs:24:13: 24:32
+ // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(<ZST>) }
+ }
+
+ bb1: {
+ StorageDead(_1); // scope 0 at $DIR/issue_72181.rs:+1:34: +1:35
+ StorageLive(_2); // scope 1 at $DIR/issue_72181.rs:+3:9: +3:10
+ StorageLive(_3); // scope 1 at $DIR/issue_72181.rs:+3:14: +3:27
+ _3 = Foo { a: const 42_u64 }; // scope 1 at $DIR/issue_72181.rs:+3:14: +3:27
+ StorageLive(_4); // scope 1 at $DIR/issue_72181.rs:+3:29: +3:42
+ _4 = Foo { a: const 10_u64 }; // scope 1 at $DIR/issue_72181.rs:+3:29: +3:42
+ _2 = [move _3, move _4]; // scope 1 at $DIR/issue_72181.rs:+3:13: +3:43
+ StorageDead(_4); // scope 1 at $DIR/issue_72181.rs:+3:42: +3:43
+ StorageDead(_3); // scope 1 at $DIR/issue_72181.rs:+3:42: +3:43
+ FakeRead(ForLet(None), _2); // scope 1 at $DIR/issue_72181.rs:+3:9: +3:10
+ StorageLive(_5); // scope 2 at $DIR/issue_72181.rs:+4:13: +4:30
+ StorageLive(_6); // scope 4 at $DIR/issue_72181.rs:+4:24: +4:25
+ _6 = const 0_usize; // scope 4 at $DIR/issue_72181.rs:+4:24: +4:25
+ _7 = Len(_2); // scope 4 at $DIR/issue_72181.rs:+4:22: +4:26
+ _8 = Lt(_6, _7); // scope 4 at $DIR/issue_72181.rs:+4:22: +4:26
+ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb2, unwind: bb3]; // scope 4 at $DIR/issue_72181.rs:+4:22: +4:26
+ }
+
+ bb2: {
+ _5 = (_2[_6].0: u64); // scope 4 at $DIR/issue_72181.rs:+4:22: +4:28
+ StorageDead(_6); // scope 2 at $DIR/issue_72181.rs:+4:30: +4:31
+ StorageDead(_5); // scope 2 at $DIR/issue_72181.rs:+4:30: +4:31
+ _0 = const (); // scope 0 at $DIR/issue_72181.rs:+0:11: +5:2
+ StorageDead(_2); // scope 1 at $DIR/issue_72181.rs:+5:1: +5:2
+ return; // scope 0 at $DIR/issue_72181.rs:+5:2: +5:2
+ }
+
+ bb3 (cleanup): {
+ resume; // scope 0 at $DIR/issue_72181.rs:+0:1: +5:2
+ }
+}
+++ /dev/null
-// MIR for `main` 0 mir_map
-
-fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/issue-72181.rs:+0:11: +0:11
- let mut _1: usize; // in scope 0 at $DIR/issue-72181.rs:+1:13: +1:34
- let mut _3: Foo; // in scope 0 at $DIR/issue-72181.rs:+3:14: +3:27
- let mut _4: Foo; // in scope 0 at $DIR/issue-72181.rs:+3:29: +3:42
- let mut _5: u64; // in scope 0 at $DIR/issue-72181.rs:+4:13: +4:30
- let _6: usize; // in scope 0 at $DIR/issue-72181.rs:+4:24: +4:25
- let mut _7: usize; // in scope 0 at $DIR/issue-72181.rs:+4:22: +4:26
- let mut _8: bool; // in scope 0 at $DIR/issue-72181.rs:+4:22: +4:26
- scope 1 {
- let _2: [Foo; 2]; // in scope 1 at $DIR/issue-72181.rs:+3:9: +3:10
- scope 2 {
- debug f => _2; // in scope 2 at $DIR/issue-72181.rs:+3:9: +3:10
- scope 3 {
- }
- scope 4 {
- }
- }
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/issue-72181.rs:+1:13: +1:34
- _1 = std::mem::size_of::<Foo>() -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-72181.rs:+1:13: +1:34
- // mir::Constant
- // + span: $DIR/issue-72181.rs:24:13: 24:32
- // + literal: Const { ty: fn() -> usize {std::mem::size_of::<Foo>}, val: Value(<ZST>) }
- }
-
- bb1: {
- StorageDead(_1); // scope 0 at $DIR/issue-72181.rs:+1:34: +1:35
- StorageLive(_2); // scope 1 at $DIR/issue-72181.rs:+3:9: +3:10
- StorageLive(_3); // scope 1 at $DIR/issue-72181.rs:+3:14: +3:27
- _3 = Foo { a: const 42_u64 }; // scope 1 at $DIR/issue-72181.rs:+3:14: +3:27
- StorageLive(_4); // scope 1 at $DIR/issue-72181.rs:+3:29: +3:42
- _4 = Foo { a: const 10_u64 }; // scope 1 at $DIR/issue-72181.rs:+3:29: +3:42
- _2 = [move _3, move _4]; // scope 1 at $DIR/issue-72181.rs:+3:13: +3:43
- StorageDead(_4); // scope 1 at $DIR/issue-72181.rs:+3:42: +3:43
- StorageDead(_3); // scope 1 at $DIR/issue-72181.rs:+3:42: +3:43
- FakeRead(ForLet(None), _2); // scope 1 at $DIR/issue-72181.rs:+3:9: +3:10
- StorageLive(_5); // scope 2 at $DIR/issue-72181.rs:+4:13: +4:30
- StorageLive(_6); // scope 4 at $DIR/issue-72181.rs:+4:24: +4:25
- _6 = const 0_usize; // scope 4 at $DIR/issue-72181.rs:+4:24: +4:25
- _7 = Len(_2); // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26
- _8 = Lt(_6, _7); // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26
- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb2, unwind: bb3]; // scope 4 at $DIR/issue-72181.rs:+4:22: +4:26
- }
-
- bb2: {
- _5 = (_2[_6].0: u64); // scope 4 at $DIR/issue-72181.rs:+4:22: +4:28
- StorageDead(_6); // scope 2 at $DIR/issue-72181.rs:+4:30: +4:31
- StorageDead(_5); // scope 2 at $DIR/issue-72181.rs:+4:30: +4:31
- _0 = const (); // scope 0 at $DIR/issue-72181.rs:+0:11: +5:2
- StorageDead(_2); // scope 1 at $DIR/issue-72181.rs:+5:1: +5:2
- return; // scope 0 at $DIR/issue-72181.rs:+5:2: +5:2
- }
-
- bb3 (cleanup): {
- resume; // scope 0 at $DIR/issue-72181.rs:+0:1: +5:2
- }
-}
--- /dev/null
+// compile-flags: -Z mir-opt-level=1
+// Regression test for #72181, this ICE requires `-Z mir-opt-level=1` flags.
+
+use std::mem;
+
+#[derive(Copy, Clone)]
+enum Never {}
+
+union Foo {
+ a: u64,
+ b: Never
+}
+
+
+// EMIT_MIR issue_72181.foo.built.after.mir
+fn foo(xs: [(Never, u32); 1]) -> u32 { xs[0].1 }
+
+// EMIT_MIR issue_72181.bar.built.after.mir
+fn bar([(_, x)]: [(Never, u32); 1]) -> u32 { x }
+
+
+// EMIT_MIR issue_72181.main.built.after.mir
+fn main() {
+ let _ = mem::size_of::<Foo>();
+
+ let f = [Foo { a: 42 }, Foo { a: 10 }];
+ let _ = unsafe { f[0].a };
+}
--- /dev/null
+// MIR for `f` after built
+
+fn f(_1: Void) -> ! {
+ debug v => _1; // in scope 0 at $DIR/issue_72181_1.rs:+0:6: +0:7
+ let mut _0: !; // return place in scope 0 at $DIR/issue_72181_1.rs:+0:18: +0:19
+ let mut _2: !; // in scope 0 at $DIR/issue_72181_1.rs:+0:20: +2:2
+ let mut _3: !; // in scope 0 at $DIR/issue_72181_1.rs:+1:5: +1:15
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/issue_72181_1.rs:+0:20: +2:2
+ StorageLive(_3); // scope 0 at $DIR/issue_72181_1.rs:+1:5: +1:15
+ FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/issue_72181_1.rs:+1:11: +1:12
+ unreachable; // scope 0 at $DIR/issue_72181_1.rs:+1:11: +1:12
+ }
+
+ bb1: {
+ unreachable; // scope 0 at $DIR/issue_72181_1.rs:+1:5: +1:15
+ }
+
+ bb2: {
+ StorageDead(_3); // scope 0 at $DIR/issue_72181_1.rs:+1:14: +1:15
+ unreachable; // scope 0 at $DIR/issue_72181_1.rs:+0:20: +2:2
+ }
+
+ bb3: {
+ StorageDead(_2); // scope 0 at $DIR/issue_72181_1.rs:+2:1: +2:2
+ return; // scope 0 at $DIR/issue_72181_1.rs:+2:2: +2:2
+ }
+}
+++ /dev/null
-// MIR for `f` 0 mir_map
-
-fn f(_1: Void) -> ! {
- debug v => _1; // in scope 0 at $DIR/issue-72181-1.rs:+0:6: +0:7
- let mut _0: !; // return place in scope 0 at $DIR/issue-72181-1.rs:+0:18: +0:19
- let mut _2: !; // in scope 0 at $DIR/issue-72181-1.rs:+0:20: +2:2
- let mut _3: !; // in scope 0 at $DIR/issue-72181-1.rs:+1:5: +1:15
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/issue-72181-1.rs:+0:20: +2:2
- StorageLive(_3); // scope 0 at $DIR/issue-72181-1.rs:+1:5: +1:15
- FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/issue-72181-1.rs:+1:11: +1:12
- unreachable; // scope 0 at $DIR/issue-72181-1.rs:+1:11: +1:12
- }
-
- bb1: {
- unreachable; // scope 0 at $DIR/issue-72181-1.rs:+1:5: +1:15
- }
-
- bb2: {
- StorageDead(_3); // scope 0 at $DIR/issue-72181-1.rs:+1:14: +1:15
- unreachable; // scope 0 at $DIR/issue-72181-1.rs:+0:20: +2:2
- }
-
- bb3: {
- StorageDead(_2); // scope 0 at $DIR/issue-72181-1.rs:+2:1: +2:2
- return; // scope 0 at $DIR/issue-72181-1.rs:+2:2: +2:2
- }
-}
--- /dev/null
+// MIR for `main` after built
+
+| User Type Annotations
+| 0: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(Void) }, span: $DIR/issue_72181_1.rs:16:12: 16:16, inferred_ty: Void
+| 1: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(Void) }, span: $DIR/issue_72181_1.rs:16:12: 16:16, inferred_ty: Void
+|
+fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/issue_72181_1.rs:+0:11: +0:11
+ let mut _1: !; // in scope 0 at $DIR/issue_72181_1.rs:+0:11: +6:2
+ let _2: Void as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/issue_72181_1.rs:+1:9: +1:10
+ let mut _3: (); // in scope 0 at $DIR/issue_72181_1.rs:+2:41: +2:43
+ let _4: !; // in scope 0 at $DIR/issue_72181_1.rs:+5:5: +5:9
+ let mut _5: Void; // in scope 0 at $DIR/issue_72181_1.rs:+5:7: +5:8
+ scope 1 {
+ debug v => _2; // in scope 1 at $DIR/issue_72181_1.rs:+1:9: +1:10
+ }
+ scope 2 {
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/issue_72181_1.rs:+1:9: +1:10
+ StorageLive(_3); // scope 2 at $DIR/issue_72181_1.rs:+2:41: +2:43
+ _3 = (); // scope 2 at $DIR/issue_72181_1.rs:+2:41: +2:43
+ _2 = transmute::<(), Void>(move _3) -> bb4; // scope 2 at $DIR/issue_72181_1.rs:+2:9: +2:44
+ // mir::Constant
+ // + span: $DIR/issue_72181_1.rs:17:9: 17:40
+ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Void {transmute::<(), Void>}, val: Value(<ZST>) }
+ }
+
+ bb1: {
+ StorageDead(_3); // scope 2 at $DIR/issue_72181_1.rs:+2:43: +2:44
+ FakeRead(ForLet(None), _2); // scope 0 at $DIR/issue_72181_1.rs:+1:9: +1:10
+ AscribeUserType(_2, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 0 at $DIR/issue_72181_1.rs:+1:12: +1:16
+ StorageLive(_4); // scope 1 at $DIR/issue_72181_1.rs:+5:5: +5:9
+ StorageLive(_5); // scope 1 at $DIR/issue_72181_1.rs:+5:7: +5:8
+ _5 = move _2; // scope 1 at $DIR/issue_72181_1.rs:+5:7: +5:8
+ _4 = f(move _5) -> bb4; // scope 1 at $DIR/issue_72181_1.rs:+5:5: +5:9
+ // mir::Constant
+ // + span: $DIR/issue_72181_1.rs:20:5: 20:6
+ // + literal: Const { ty: fn(Void) -> ! {f}, val: Value(<ZST>) }
+ }
+
+ bb2: {
+ StorageDead(_5); // scope 1 at $DIR/issue_72181_1.rs:+5:8: +5:9
+ StorageDead(_4); // scope 1 at $DIR/issue_72181_1.rs:+5:9: +5:10
+ StorageDead(_2); // scope 0 at $DIR/issue_72181_1.rs:+6:1: +6:2
+ unreachable; // scope 0 at $DIR/issue_72181_1.rs:+0:11: +6:2
+ }
+
+ bb3: {
+ return; // scope 0 at $DIR/issue_72181_1.rs:+6:2: +6:2
+ }
+
+ bb4 (cleanup): {
+ resume; // scope 0 at $DIR/issue_72181_1.rs:+0:1: +6:2
+ }
+}
+++ /dev/null
-// MIR for `main` 0 mir_map
-
-| User Type Annotations
-| 0: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(Void) }, span: $DIR/issue-72181-1.rs:16:12: 16:16, inferred_ty: Void
-| 1: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(Void) }, span: $DIR/issue-72181-1.rs:16:12: 16:16, inferred_ty: Void
-|
-fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/issue-72181-1.rs:+0:11: +0:11
- let mut _1: !; // in scope 0 at $DIR/issue-72181-1.rs:+0:11: +6:2
- let _2: Void as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/issue-72181-1.rs:+1:9: +1:10
- let mut _3: (); // in scope 0 at $DIR/issue-72181-1.rs:+2:41: +2:43
- let _4: !; // in scope 0 at $DIR/issue-72181-1.rs:+5:5: +5:9
- let mut _5: Void; // in scope 0 at $DIR/issue-72181-1.rs:+5:7: +5:8
- scope 1 {
- debug v => _2; // in scope 1 at $DIR/issue-72181-1.rs:+1:9: +1:10
- }
- scope 2 {
- }
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/issue-72181-1.rs:+1:9: +1:10
- StorageLive(_3); // scope 2 at $DIR/issue-72181-1.rs:+2:41: +2:43
- _3 = (); // scope 2 at $DIR/issue-72181-1.rs:+2:41: +2:43
- _2 = transmute::<(), Void>(move _3) -> bb4; // scope 2 at $DIR/issue-72181-1.rs:+2:9: +2:44
- // mir::Constant
- // + span: $DIR/issue-72181-1.rs:17:9: 17:40
- // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Void {transmute::<(), Void>}, val: Value(<ZST>) }
- }
-
- bb1: {
- StorageDead(_3); // scope 2 at $DIR/issue-72181-1.rs:+2:43: +2:44
- FakeRead(ForLet(None), _2); // scope 0 at $DIR/issue-72181-1.rs:+1:9: +1:10
- AscribeUserType(_2, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 0 at $DIR/issue-72181-1.rs:+1:12: +1:16
- StorageLive(_4); // scope 1 at $DIR/issue-72181-1.rs:+5:5: +5:9
- StorageLive(_5); // scope 1 at $DIR/issue-72181-1.rs:+5:7: +5:8
- _5 = move _2; // scope 1 at $DIR/issue-72181-1.rs:+5:7: +5:8
- _4 = f(move _5) -> bb4; // scope 1 at $DIR/issue-72181-1.rs:+5:5: +5:9
- // mir::Constant
- // + span: $DIR/issue-72181-1.rs:20:5: 20:6
- // + literal: Const { ty: fn(Void) -> ! {f}, val: Value(<ZST>) }
- }
-
- bb2: {
- StorageDead(_5); // scope 1 at $DIR/issue-72181-1.rs:+5:8: +5:9
- StorageDead(_4); // scope 1 at $DIR/issue-72181-1.rs:+5:9: +5:10
- StorageDead(_2); // scope 0 at $DIR/issue-72181-1.rs:+6:1: +6:2
- unreachable; // scope 0 at $DIR/issue-72181-1.rs:+0:11: +6:2
- }
-
- bb3: {
- return; // scope 0 at $DIR/issue-72181-1.rs:+6:2: +6:2
- }
-
- bb4 (cleanup): {
- resume; // scope 0 at $DIR/issue-72181-1.rs:+0:1: +6:2
- }
-}
--- /dev/null
+// compile-flags: -Z mir-opt-level=1
+// Regression test for #72181, this ICE requires `-Z mir-opt-level=1` flags.
+
+#![feature(never_type)]
+#![allow(unused, invalid_value)]
+
+enum Void {}
+
+// EMIT_MIR issue_72181_1.f.built.after.mir
+fn f(v: Void) -> ! {
+ match v {}
+}
+
+// EMIT_MIR issue_72181_1.main.built.after.mir
+fn main() {
+ let v: Void = unsafe {
+ std::mem::transmute::<(), Void>(())
+ };
+
+ f(v);
+}
+ // MIR for `main` after SimplifyArmIdentity
fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:+0:11: +0:11
- let _1: i32; // in scope 0 at $DIR/issue-73223.rs:+1:9: +1:14
- let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- let mut _3: isize; // in scope 0 at $DIR/issue-73223.rs:+2:9: +2:16
- let _4: i32; // in scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
- let mut _5: !; // in scope 0 at $DIR/issue-73223.rs:+3:17: +3:23
- let mut _7: i32; // in scope 0 at $DIR/issue-73223.rs:+6:22: +6:27
+ let mut _0: (); // return place in scope 0 at $DIR/issue_73223.rs:+0:11: +0:11
+ let _1: i32; // in scope 0 at $DIR/issue_73223.rs:+1:9: +1:14
+ let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue_73223.rs:+1:23: +1:30
+ let mut _3: isize; // in scope 0 at $DIR/issue_73223.rs:+2:9: +2:16
+ let _4: i32; // in scope 0 at $DIR/issue_73223.rs:+2:14: +2:15
+ let mut _5: !; // in scope 0 at $DIR/issue_73223.rs:+3:17: +3:23
+ let mut _7: i32; // in scope 0 at $DIR/issue_73223.rs:+6:22: +6:27
let _8: (); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let mut _9: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let mut _10: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let mut _11: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _12: i32; // in scope 0 at $DIR/issue-73223.rs:+7:23: +7:24
+ let _12: i32; // in scope 0 at $DIR/issue_73223.rs:+7:23: +7:24
let mut _15: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let mut _16: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let mut _17: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let _26: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let mut _27: std::option::Option<std::fmt::Arguments<'_>>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
scope 1 {
- debug split => _1; // in scope 1 at $DIR/issue-73223.rs:+1:9: +1:14
- let _6: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:+6:9: +6:14
+ debug split => _1; // in scope 1 at $DIR/issue_73223.rs:+1:9: +1:14
+ let _6: std::option::Option<i32>; // in scope 1 at $DIR/issue_73223.rs:+6:9: +6:14
scope 3 {
- debug _prev => _6; // in scope 3 at $DIR/issue-73223.rs:+6:9: +6:14
+ debug _prev => _6; // in scope 3 at $DIR/issue_73223.rs:+6:9: +6:14
let _13: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let _14: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
let mut _28: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
}
}
scope 2 {
- debug v => _4; // in scope 2 at $DIR/issue-73223.rs:+2:14: +2:15
+ debug v => _4; // in scope 2 at $DIR/issue_73223.rs:+2:14: +2:15
}
bb0: {
- StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:+1:9: +1:14
- StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- Deinit(_2); // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- _3 = const 1_isize; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
- goto -> bb3; // scope 0 at $DIR/issue-73223.rs:+1:17: +1:30
+ StorageLive(_1); // scope 0 at $DIR/issue_73223.rs:+1:9: +1:14
+ StorageLive(_2); // scope 0 at $DIR/issue_73223.rs:+1:23: +1:30
+ Deinit(_2); // scope 0 at $DIR/issue_73223.rs:+1:23: +1:30
+ ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue_73223.rs:+1:23: +1:30
+ discriminant(_2) = 1; // scope 0 at $DIR/issue_73223.rs:+1:23: +1:30
+ _3 = const 1_isize; // scope 0 at $DIR/issue_73223.rs:+1:23: +1:30
+ goto -> bb3; // scope 0 at $DIR/issue_73223.rs:+1:17: +1:30
}
bb1: {
- nop; // scope 0 at $DIR/issue-73223.rs:+3:17: +3:23
- StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7
- StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2
- return; // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2
+ nop; // scope 0 at $DIR/issue_73223.rs:+3:17: +3:23
+ StorageDead(_2); // scope 0 at $DIR/issue_73223.rs:+4:6: +4:7
+ StorageDead(_1); // scope 0 at $DIR/issue_73223.rs:+8:1: +8:2
+ return; // scope 0 at $DIR/issue_73223.rs:+8:2: +8:2
}
bb2: {
- unreachable; // scope 0 at $DIR/issue-73223.rs:+1:23: +1:30
+ unreachable; // scope 0 at $DIR/issue_73223.rs:+1:23: +1:30
}
bb3: {
- StorageLive(_4); // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
- _4 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:+2:14: +2:15
- _1 = _4; // scope 2 at $DIR/issue-73223.rs:+2:20: +2:21
- StorageDead(_4); // scope 0 at $DIR/issue-73223.rs:+2:20: +2:21
- StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:+4:6: +4:7
- StorageLive(_6); // scope 1 at $DIR/issue-73223.rs:+6:9: +6:14
- StorageLive(_7); // scope 1 at $DIR/issue-73223.rs:+6:22: +6:27
- _7 = _1; // scope 1 at $DIR/issue-73223.rs:+6:22: +6:27
- Deinit(_6); // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28
- ((_6 as Some).0: i32) = move _7; // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28
- discriminant(_6) = 1; // scope 1 at $DIR/issue-73223.rs:+6:17: +6:28
- StorageDead(_7); // scope 1 at $DIR/issue-73223.rs:+6:27: +6:28
+ StorageLive(_4); // scope 0 at $DIR/issue_73223.rs:+2:14: +2:15
+ _4 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue_73223.rs:+2:14: +2:15
+ _1 = _4; // scope 2 at $DIR/issue_73223.rs:+2:20: +2:21
+ StorageDead(_4); // scope 0 at $DIR/issue_73223.rs:+2:20: +2:21
+ StorageDead(_2); // scope 0 at $DIR/issue_73223.rs:+4:6: +4:7
+ StorageLive(_6); // scope 1 at $DIR/issue_73223.rs:+6:9: +6:14
+ StorageLive(_7); // scope 1 at $DIR/issue_73223.rs:+6:22: +6:27
+ _7 = _1; // scope 1 at $DIR/issue_73223.rs:+6:22: +6:27
+ Deinit(_6); // scope 1 at $DIR/issue_73223.rs:+6:17: +6:28
+ ((_6 as Some).0: i32) = move _7; // scope 1 at $DIR/issue_73223.rs:+6:17: +6:28
+ discriminant(_6) = 1; // scope 1 at $DIR/issue_73223.rs:+6:17: +6:28
+ StorageDead(_7); // scope 1 at $DIR/issue_73223.rs:+6:27: +6:28
StorageLive(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageLive(_10); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageDead(_13); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageDead(_9); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageDead(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- nop; // scope 0 at $DIR/issue-73223.rs:+0:11: +8:2
- StorageDead(_6); // scope 1 at $DIR/issue-73223.rs:+8:1: +8:2
- StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:+8:1: +8:2
- return; // scope 0 at $DIR/issue-73223.rs:+8:2: +8:2
+ nop; // scope 0 at $DIR/issue_73223.rs:+0:11: +8:2
+ StorageDead(_6); // scope 1 at $DIR/issue_73223.rs:+8:1: +8:2
+ StorageDead(_1); // scope 0 at $DIR/issue_73223.rs:+8:1: +8:2
+ return; // scope 0 at $DIR/issue_73223.rs:+8:2: +8:2
}
}
--- /dev/null
+fn main() {
+ let split = match Some(1) {
+ Some(v) => v,
+ None => return,
+ };
+
+ let _prev = Some(split);
+ assert_eq!(split, 1);
+}
+
+
+// EMIT_MIR issue_73223.main.SimplifyArmIdentity.diff
+ // MIR for `f` after InstCombine
fn f(_1: &T) -> *const T {
- debug a => _1; // in scope 0 at $DIR/issue-78192.rs:+0:13: +0:14
- let mut _0: *const T; // return place in scope 0 at $DIR/issue-78192.rs:+0:23: +0:31
- let _2: &*const T; // in scope 0 at $DIR/issue-78192.rs:+1:9: +1:10
- let _3: &*const T; // in scope 0 at $DIR/issue-78192.rs:+1:24: +1:40
- let _4: *const T; // in scope 0 at $DIR/issue-78192.rs:+1:25: +1:40
+ debug a => _1; // in scope 0 at $DIR/issue_78192.rs:+0:13: +0:14
+ let mut _0: *const T; // return place in scope 0 at $DIR/issue_78192.rs:+0:23: +0:31
+ let _2: &*const T; // in scope 0 at $DIR/issue_78192.rs:+1:9: +1:10
+ let _3: &*const T; // in scope 0 at $DIR/issue_78192.rs:+1:24: +1:40
+ let _4: *const T; // in scope 0 at $DIR/issue_78192.rs:+1:25: +1:40
scope 1 {
- debug b => _2; // in scope 1 at $DIR/issue-78192.rs:+1:9: +1:10
+ debug b => _2; // in scope 1 at $DIR/issue_78192.rs:+1:9: +1:10
}
bb0: {
- StorageLive(_2); // scope 0 at $DIR/issue-78192.rs:+1:9: +1:10
- StorageLive(_3); // scope 0 at $DIR/issue-78192.rs:+1:24: +1:40
- StorageLive(_4); // scope 0 at $DIR/issue-78192.rs:+1:25: +1:40
- _4 = &raw const (*_1); // scope 0 at $DIR/issue-78192.rs:+1:26: +1:27
- _3 = &_4; // scope 0 at $DIR/issue-78192.rs:+1:24: +1:40
-- _2 = &(*_3); // scope 0 at $DIR/issue-78192.rs:+1:24: +1:40
-+ _2 = _3; // scope 0 at $DIR/issue-78192.rs:+1:24: +1:40
- StorageDead(_3); // scope 0 at $DIR/issue-78192.rs:+1:40: +1:41
- _0 = (*_2); // scope 1 at $DIR/issue-78192.rs:+2:5: +2:7
- StorageDead(_4); // scope 0 at $DIR/issue-78192.rs:+3:1: +3:2
- StorageDead(_2); // scope 0 at $DIR/issue-78192.rs:+3:1: +3:2
- return; // scope 0 at $DIR/issue-78192.rs:+3:2: +3:2
+ StorageLive(_2); // scope 0 at $DIR/issue_78192.rs:+1:9: +1:10
+ StorageLive(_3); // scope 0 at $DIR/issue_78192.rs:+1:24: +1:40
+ StorageLive(_4); // scope 0 at $DIR/issue_78192.rs:+1:25: +1:40
+ _4 = &raw const (*_1); // scope 0 at $DIR/issue_78192.rs:+1:26: +1:27
+ _3 = &_4; // scope 0 at $DIR/issue_78192.rs:+1:24: +1:40
+- _2 = &(*_3); // scope 0 at $DIR/issue_78192.rs:+1:24: +1:40
++ _2 = _3; // scope 0 at $DIR/issue_78192.rs:+1:24: +1:40
+ StorageDead(_3); // scope 0 at $DIR/issue_78192.rs:+1:40: +1:41
+ _0 = (*_2); // scope 1 at $DIR/issue_78192.rs:+2:5: +2:7
+ StorageDead(_4); // scope 0 at $DIR/issue_78192.rs:+3:1: +3:2
+ StorageDead(_2); // scope 0 at $DIR/issue_78192.rs:+3:1: +3:2
+ return; // scope 0 at $DIR/issue_78192.rs:+3:2: +3:2
}
}
--- /dev/null
+// compile-flags: -Zmir-opt-level=1 -Zinline-mir
+pub fn f<T>(a: &T) -> *const T {
+ let b: &*const T = &(a as *const T);
+ *b
+}
+
+fn main() {
+ f(&2);
+}
+
+// EMIT_MIR issue_78192.f.InstCombine.diff
--- /dev/null
+// MIR for `bar` after built
+
+fn bar(_1: Box<[T]>) -> () {
+ debug it => _1; // in scope 0 at $DIR/issue_91633.rs:+0:12: +0:14
+ let mut _0: (); // return place in scope 0 at $DIR/issue_91633.rs:+1:2: +1:2
+ let mut _2: &<[T] as std::ops::Index<usize>>::Output; // in scope 0 at $DIR/issue_91633.rs:+4:14: +4:19
+ let mut _3: &[T]; // in scope 0 at $DIR/issue_91633.rs:+4:14: +4:16
+ scope 1 {
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/issue_91633.rs:+4:14: +4:19
+ StorageLive(_3); // scope 0 at $DIR/issue_91633.rs:+4:14: +4:16
+ _3 = &(*_1); // scope 0 at $DIR/issue_91633.rs:+4:14: +4:16
+ _2 = <[T] as Index<usize>>::index(move _3, const 0_usize) -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue_91633.rs:+4:14: +4:19
+ // mir::Constant
+ // + span: $DIR/issue_91633.rs:15:14: 15:19
+ // + literal: Const { ty: for<'a> fn(&'a [T], usize) -> &'a <[T] as Index<usize>>::Output {<[T] as Index<usize>>::index}, val: Value(<ZST>) }
+ }
+
+ bb1: {
+ StorageDead(_3); // scope 0 at $DIR/issue_91633.rs:+4:18: +4:19
+ StorageDead(_2); // scope 0 at $DIR/issue_91633.rs:+4:19: +4:20
+ _0 = const (); // scope 0 at $DIR/issue_91633.rs:+3:2: +5:3
+ drop(_1) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue_91633.rs:+5:2: +5:3
+ }
+
+ bb2: {
+ return; // scope 0 at $DIR/issue_91633.rs:+5:3: +5:3
+ }
+
+ bb3 (cleanup): {
+ drop(_1) -> bb4; // scope 0 at $DIR/issue_91633.rs:+5:2: +5:3
+ }
+
+ bb4 (cleanup): {
+ resume; // scope 0 at $DIR/issue_91633.rs:+0:1: +5:3
+ }
+}
+++ /dev/null
-// MIR for `bar` 0 mir_map
-
-fn bar(_1: Box<[T]>) -> () {
- debug it => _1; // in scope 0 at $DIR/issue-91633.rs:+0:12: +0:14
- let mut _0: (); // return place in scope 0 at $DIR/issue-91633.rs:+1:2: +1:2
- let mut _2: &<[T] as std::ops::Index<usize>>::Output; // in scope 0 at $DIR/issue-91633.rs:+4:14: +4:19
- let mut _3: &[T]; // in scope 0 at $DIR/issue-91633.rs:+4:14: +4:16
- scope 1 {
- }
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/issue-91633.rs:+4:14: +4:19
- StorageLive(_3); // scope 0 at $DIR/issue-91633.rs:+4:14: +4:16
- _3 = &(*_1); // scope 0 at $DIR/issue-91633.rs:+4:14: +4:16
- _2 = <[T] as Index<usize>>::index(move _3, const 0_usize) -> [return: bb1, unwind: bb3]; // scope 0 at $DIR/issue-91633.rs:+4:14: +4:19
- // mir::Constant
- // + span: $DIR/issue-91633.rs:15:14: 15:19
- // + literal: Const { ty: for<'a> fn(&'a [T], usize) -> &'a <[T] as Index<usize>>::Output {<[T] as Index<usize>>::index}, val: Value(<ZST>) }
- }
-
- bb1: {
- StorageDead(_3); // scope 0 at $DIR/issue-91633.rs:+4:18: +4:19
- StorageDead(_2); // scope 0 at $DIR/issue-91633.rs:+4:19: +4:20
- _0 = const (); // scope 0 at $DIR/issue-91633.rs:+3:2: +5:3
- drop(_1) -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/issue-91633.rs:+5:2: +5:3
- }
-
- bb2: {
- return; // scope 0 at $DIR/issue-91633.rs:+5:3: +5:3
- }
-
- bb3 (cleanup): {
- drop(_1) -> bb4; // scope 0 at $DIR/issue-91633.rs:+5:2: +5:3
- }
-
- bb4 (cleanup): {
- resume; // scope 0 at $DIR/issue-91633.rs:+0:1: +5:3
- }
-}
--- /dev/null
+// MIR for `foo` after built
+
+fn foo(_1: Box<[T]>) -> T {
+ debug it => _1; // in scope 0 at $DIR/issue_91633.rs:+0:19: +0:21
+ let mut _0: T; // return place in scope 0 at $DIR/issue_91633.rs:+0:36: +0:37
+ let _2: T; // in scope 0 at $DIR/issue_91633.rs:+2:10: +2:11
+ let mut _3: &T; // in scope 0 at $DIR/issue_91633.rs:+2:14: +2:27
+ let _4: usize; // in scope 0 at $DIR/issue_91633.rs:+2:17: +2:18
+ let mut _5: usize; // in scope 0 at $DIR/issue_91633.rs:+2:14: +2:19
+ let mut _6: bool; // in scope 0 at $DIR/issue_91633.rs:+2:14: +2:19
+ scope 1 {
+ debug f => _2; // in scope 1 at $DIR/issue_91633.rs:+2:10: +2:11
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/issue_91633.rs:+2:10: +2:11
+ StorageLive(_3); // scope 0 at $DIR/issue_91633.rs:+2:14: +2:27
+ StorageLive(_4); // scope 0 at $DIR/issue_91633.rs:+2:17: +2:18
+ _4 = const 0_usize; // scope 0 at $DIR/issue_91633.rs:+2:17: +2:18
+ _5 = Len((*_1)); // scope 0 at $DIR/issue_91633.rs:+2:14: +2:19
+ _6 = Lt(_4, _5); // scope 0 at $DIR/issue_91633.rs:+2:14: +2:19
+ assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind: bb5]; // scope 0 at $DIR/issue_91633.rs:+2:14: +2:19
+ }
+
+ bb1: {
+ _3 = &(*_1)[_4]; // scope 0 at $DIR/issue_91633.rs:+2:14: +2:27
+ _2 = <T as Clone>::clone(move _3) -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/issue_91633.rs:+2:14: +2:27
+ // mir::Constant
+ // + span: $DIR/issue_91633.rs:28:20: 28:25
+ // + literal: Const { ty: for<'a> fn(&'a T) -> T {<T as Clone>::clone}, val: Value(<ZST>) }
+ }
+
+ bb2: {
+ StorageDead(_3); // scope 0 at $DIR/issue_91633.rs:+2:26: +2:27
+ FakeRead(ForLet(None), _2); // scope 0 at $DIR/issue_91633.rs:+2:10: +2:11
+ StorageDead(_4); // scope 0 at $DIR/issue_91633.rs:+2:27: +2:28
+ _0 = move _2; // scope 1 at $DIR/issue_91633.rs:+3:6: +3:7
+ drop(_2) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/issue_91633.rs:+4:2: +4:3
+ }
+
+ bb3: {
+ StorageDead(_2); // scope 0 at $DIR/issue_91633.rs:+4:2: +4:3
+ drop(_1) -> [return: bb4, unwind: bb6]; // scope 0 at $DIR/issue_91633.rs:+4:2: +4:3
+ }
+
+ bb4: {
+ return; // scope 0 at $DIR/issue_91633.rs:+4:3: +4:3
+ }
+
+ bb5 (cleanup): {
+ drop(_1) -> bb6; // scope 0 at $DIR/issue_91633.rs:+4:2: +4:3
+ }
+
+ bb6 (cleanup): {
+ resume; // scope 0 at $DIR/issue_91633.rs:+0:1: +4:3
+ }
+}
+++ /dev/null
-// MIR for `foo` 0 mir_map
-
-fn foo(_1: Box<[T]>) -> T {
- debug it => _1; // in scope 0 at $DIR/issue-91633.rs:+0:19: +0:21
- let mut _0: T; // return place in scope 0 at $DIR/issue-91633.rs:+0:36: +0:37
- let _2: T; // in scope 0 at $DIR/issue-91633.rs:+2:10: +2:11
- let mut _3: &T; // in scope 0 at $DIR/issue-91633.rs:+2:14: +2:27
- let _4: usize; // in scope 0 at $DIR/issue-91633.rs:+2:17: +2:18
- let mut _5: usize; // in scope 0 at $DIR/issue-91633.rs:+2:14: +2:19
- let mut _6: bool; // in scope 0 at $DIR/issue-91633.rs:+2:14: +2:19
- scope 1 {
- debug f => _2; // in scope 1 at $DIR/issue-91633.rs:+2:10: +2:11
- }
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/issue-91633.rs:+2:10: +2:11
- StorageLive(_3); // scope 0 at $DIR/issue-91633.rs:+2:14: +2:27
- StorageLive(_4); // scope 0 at $DIR/issue-91633.rs:+2:17: +2:18
- _4 = const 0_usize; // scope 0 at $DIR/issue-91633.rs:+2:17: +2:18
- _5 = Len((*_1)); // scope 0 at $DIR/issue-91633.rs:+2:14: +2:19
- _6 = Lt(_4, _5); // scope 0 at $DIR/issue-91633.rs:+2:14: +2:19
- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> [success: bb1, unwind: bb5]; // scope 0 at $DIR/issue-91633.rs:+2:14: +2:19
- }
-
- bb1: {
- _3 = &(*_1)[_4]; // scope 0 at $DIR/issue-91633.rs:+2:14: +2:27
- _2 = <T as Clone>::clone(move _3) -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/issue-91633.rs:+2:14: +2:27
- // mir::Constant
- // + span: $DIR/issue-91633.rs:28:20: 28:25
- // + literal: Const { ty: for<'a> fn(&'a T) -> T {<T as Clone>::clone}, val: Value(<ZST>) }
- }
-
- bb2: {
- StorageDead(_3); // scope 0 at $DIR/issue-91633.rs:+2:26: +2:27
- FakeRead(ForLet(None), _2); // scope 0 at $DIR/issue-91633.rs:+2:10: +2:11
- StorageDead(_4); // scope 0 at $DIR/issue-91633.rs:+2:27: +2:28
- _0 = move _2; // scope 1 at $DIR/issue-91633.rs:+3:6: +3:7
- drop(_2) -> [return: bb3, unwind: bb5]; // scope 0 at $DIR/issue-91633.rs:+4:2: +4:3
- }
-
- bb3: {
- StorageDead(_2); // scope 0 at $DIR/issue-91633.rs:+4:2: +4:3
- drop(_1) -> [return: bb4, unwind: bb6]; // scope 0 at $DIR/issue-91633.rs:+4:2: +4:3
- }
-
- bb4: {
- return; // scope 0 at $DIR/issue-91633.rs:+4:3: +4:3
- }
-
- bb5 (cleanup): {
- drop(_1) -> bb6; // scope 0 at $DIR/issue-91633.rs:+4:2: +4:3
- }
-
- bb6 (cleanup): {
- resume; // scope 0 at $DIR/issue-91633.rs:+0:1: +4:3
- }
-}
--- /dev/null
+// MIR for `fun` after built
+
+fn fun(_1: &[T]) -> &T {
+ debug it => _1; // in scope 0 at $DIR/issue_91633.rs:+0:12: +0:14
+ let mut _0: &T; // return place in scope 0 at $DIR/issue_91633.rs:+0:25: +0:27
+ let _2: &T; // in scope 0 at $DIR/issue_91633.rs:+2:10: +2:11
+ let _3: usize; // in scope 0 at $DIR/issue_91633.rs:+2:18: +2:19
+ let mut _4: usize; // in scope 0 at $DIR/issue_91633.rs:+2:15: +2:20
+ let mut _5: bool; // in scope 0 at $DIR/issue_91633.rs:+2:15: +2:20
+ scope 1 {
+ debug f => _2; // in scope 1 at $DIR/issue_91633.rs:+2:10: +2:11
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/issue_91633.rs:+2:10: +2:11
+ StorageLive(_3); // scope 0 at $DIR/issue_91633.rs:+2:18: +2:19
+ _3 = const 0_usize; // scope 0 at $DIR/issue_91633.rs:+2:18: +2:19
+ _4 = Len((*_1)); // scope 0 at $DIR/issue_91633.rs:+2:15: +2:20
+ _5 = Lt(_3, _4); // scope 0 at $DIR/issue_91633.rs:+2:15: +2:20
+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue_91633.rs:+2:15: +2:20
+ }
+
+ bb1: {
+ _2 = &(*_1)[_3]; // scope 0 at $DIR/issue_91633.rs:+2:14: +2:20
+ FakeRead(ForLet(None), _2); // scope 0 at $DIR/issue_91633.rs:+2:10: +2:11
+ _0 = &(*_2); // scope 1 at $DIR/issue_91633.rs:+3:6: +3:7
+ StorageDead(_3); // scope 0 at $DIR/issue_91633.rs:+4:2: +4:3
+ StorageDead(_2); // scope 0 at $DIR/issue_91633.rs:+4:2: +4:3
+ return; // scope 0 at $DIR/issue_91633.rs:+4:3: +4:3
+ }
+
+ bb2 (cleanup): {
+ resume; // scope 0 at $DIR/issue_91633.rs:+0:1: +4:3
+ }
+}
+++ /dev/null
-// MIR for `fun` 0 mir_map
-
-fn fun(_1: &[T]) -> &T {
- debug it => _1; // in scope 0 at $DIR/issue-91633.rs:+0:12: +0:14
- let mut _0: &T; // return place in scope 0 at $DIR/issue-91633.rs:+0:25: +0:27
- let _2: &T; // in scope 0 at $DIR/issue-91633.rs:+2:10: +2:11
- let _3: usize; // in scope 0 at $DIR/issue-91633.rs:+2:18: +2:19
- let mut _4: usize; // in scope 0 at $DIR/issue-91633.rs:+2:15: +2:20
- let mut _5: bool; // in scope 0 at $DIR/issue-91633.rs:+2:15: +2:20
- scope 1 {
- debug f => _2; // in scope 1 at $DIR/issue-91633.rs:+2:10: +2:11
- }
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/issue-91633.rs:+2:10: +2:11
- StorageLive(_3); // scope 0 at $DIR/issue-91633.rs:+2:18: +2:19
- _3 = const 0_usize; // scope 0 at $DIR/issue-91633.rs:+2:18: +2:19
- _4 = Len((*_1)); // scope 0 at $DIR/issue-91633.rs:+2:15: +2:20
- _5 = Lt(_3, _4); // scope 0 at $DIR/issue-91633.rs:+2:15: +2:20
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind: bb2]; // scope 0 at $DIR/issue-91633.rs:+2:15: +2:20
- }
-
- bb1: {
- _2 = &(*_1)[_3]; // scope 0 at $DIR/issue-91633.rs:+2:14: +2:20
- FakeRead(ForLet(None), _2); // scope 0 at $DIR/issue-91633.rs:+2:10: +2:11
- _0 = &(*_2); // scope 1 at $DIR/issue-91633.rs:+3:6: +3:7
- StorageDead(_3); // scope 0 at $DIR/issue-91633.rs:+4:2: +4:3
- StorageDead(_2); // scope 0 at $DIR/issue-91633.rs:+4:2: +4:3
- return; // scope 0 at $DIR/issue-91633.rs:+4:3: +4:3
- }
-
- bb2 (cleanup): {
- resume; // scope 0 at $DIR/issue-91633.rs:+0:1: +4:3
- }
-}
--- /dev/null
+// MIR for `hey` after built
+
+fn hey(_1: &[T]) -> () {
+ debug it => _1; // in scope 0 at $DIR/issue_91633.rs:+0:12: +0:14
+ let mut _0: (); // return place in scope 0 at $DIR/issue_91633.rs:+1:2: +1:2
+ let mut _2: &<[T] as std::ops::Index<usize>>::Output; // in scope 0 at $DIR/issue_91633.rs:+4:14: +4:20
+ let _3: &<[T] as std::ops::Index<usize>>::Output; // in scope 0 at $DIR/issue_91633.rs:+4:15: +4:20
+ let mut _4: &[T]; // in scope 0 at $DIR/issue_91633.rs:+4:15: +4:17
+ scope 1 {
+ }
+
+ bb0: {
+ StorageLive(_2); // scope 0 at $DIR/issue_91633.rs:+4:14: +4:20
+ StorageLive(_3); // scope 0 at $DIR/issue_91633.rs:+4:15: +4:20
+ StorageLive(_4); // scope 0 at $DIR/issue_91633.rs:+4:15: +4:17
+ _4 = &(*_1); // scope 0 at $DIR/issue_91633.rs:+4:15: +4:17
+ _3 = <[T] as Index<usize>>::index(move _4, const 0_usize) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/issue_91633.rs:+4:15: +4:20
+ // mir::Constant
+ // + span: $DIR/issue_91633.rs:7:15: 7:20
+ // + literal: Const { ty: for<'a> fn(&'a [T], usize) -> &'a <[T] as Index<usize>>::Output {<[T] as Index<usize>>::index}, val: Value(<ZST>) }
+ }
+
+ bb1: {
+ StorageDead(_4); // scope 0 at $DIR/issue_91633.rs:+4:19: +4:20
+ _2 = &(*_3); // scope 0 at $DIR/issue_91633.rs:+4:14: +4:20
+ StorageDead(_2); // scope 0 at $DIR/issue_91633.rs:+4:20: +4:21
+ _0 = const (); // scope 0 at $DIR/issue_91633.rs:+3:2: +5:3
+ StorageDead(_3); // scope 0 at $DIR/issue_91633.rs:+5:2: +5:3
+ return; // scope 0 at $DIR/issue_91633.rs:+5:3: +5:3
+ }
+
+ bb2 (cleanup): {
+ resume; // scope 0 at $DIR/issue_91633.rs:+0:1: +5:3
+ }
+}
+++ /dev/null
-// MIR for `hey` 0 mir_map
-
-fn hey(_1: &[T]) -> () {
- debug it => _1; // in scope 0 at $DIR/issue-91633.rs:+0:12: +0:14
- let mut _0: (); // return place in scope 0 at $DIR/issue-91633.rs:+1:2: +1:2
- let mut _2: &<[T] as std::ops::Index<usize>>::Output; // in scope 0 at $DIR/issue-91633.rs:+4:14: +4:20
- let _3: &<[T] as std::ops::Index<usize>>::Output; // in scope 0 at $DIR/issue-91633.rs:+4:15: +4:20
- let mut _4: &[T]; // in scope 0 at $DIR/issue-91633.rs:+4:15: +4:17
- scope 1 {
- }
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/issue-91633.rs:+4:14: +4:20
- StorageLive(_3); // scope 0 at $DIR/issue-91633.rs:+4:15: +4:20
- StorageLive(_4); // scope 0 at $DIR/issue-91633.rs:+4:15: +4:17
- _4 = &(*_1); // scope 0 at $DIR/issue-91633.rs:+4:15: +4:17
- _3 = <[T] as Index<usize>>::index(move _4, const 0_usize) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/issue-91633.rs:+4:15: +4:20
- // mir::Constant
- // + span: $DIR/issue-91633.rs:7:15: 7:20
- // + literal: Const { ty: for<'a> fn(&'a [T], usize) -> &'a <[T] as Index<usize>>::Output {<[T] as Index<usize>>::index}, val: Value(<ZST>) }
- }
-
- bb1: {
- StorageDead(_4); // scope 0 at $DIR/issue-91633.rs:+4:19: +4:20
- _2 = &(*_3); // scope 0 at $DIR/issue-91633.rs:+4:14: +4:20
- StorageDead(_2); // scope 0 at $DIR/issue-91633.rs:+4:20: +4:21
- _0 = const (); // scope 0 at $DIR/issue-91633.rs:+3:2: +5:3
- StorageDead(_3); // scope 0 at $DIR/issue-91633.rs:+5:2: +5:3
- return; // scope 0 at $DIR/issue-91633.rs:+5:3: +5:3
- }
-
- bb2 (cleanup): {
- resume; // scope 0 at $DIR/issue-91633.rs:+0:1: +5:3
- }
-}
--- /dev/null
+// compile-flags: -Z mir-opt-level=0
+// EMIT_MIR issue_91633.hey.built.after.mir
+fn hey<T> (it: &[T])
+ where
+ [T] : std::ops::Index<usize>,
+ {
+ let _ = &it[0];
+ }
+
+// EMIT_MIR issue_91633.bar.built.after.mir
+fn bar<T> (it: Box<[T]>)
+ where
+ [T] : std::ops::Index<usize>,
+ {
+ let _ = it[0];
+ }
+
+// EMIT_MIR issue_91633.fun.built.after.mir
+fn fun<T> (it: &[T]) -> &T
+ {
+ let f = &it[0];
+ f
+ }
+
+// EMIT_MIR issue_91633.foo.built.after.mir
+fn foo<T: Clone> (it: Box<[T]>) -> T
+ {
+ let f = it[0].clone();
+ f
+ }
+ fn main(){}
--- /dev/null
+// MIR for `main` after built
+
+| User Type Annotations
+| 0: user_ty: Canonical { max_universe: U0, variables: [], value: TypeOf(DefId(0:3 ~ issue_99325[8f58]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: Value(Branch([Leaf(0x41), Leaf(0x41), Leaf(0x41), Leaf(0x41)])) }], user_self_ty: None }) }, span: $DIR/issue_99325.rs:10:16: 10:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+| 1: user_ty: Canonical { max_universe: U0, variables: [], value: TypeOf(DefId(0:3 ~ issue_99325[8f58]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: Unevaluated(UnevaluatedConst { def: WithOptConstParam { did: DefId(0:8 ~ issue_99325[8f58]::main::{constant#1}), const_param_did: Some(DefId(0:4 ~ issue_99325[8f58]::function_with_bytes::BYTES)) }, substs: [] }) }], user_self_ty: None }) }, span: $DIR/issue_99325.rs:11:16: 11:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
+|
+fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/issue_99325.rs:+0:15: +0:15
+ let _1: (); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _2: (&&[u8], &&[u8; 4]); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _3: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _4: &[u8]; // in scope 0 at $DIR/issue_99325.rs:+1:16: +1:48
+ let mut _5: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _6: &[u8; 4]; // in scope 0 at $DIR/issue_99325.rs:+1:50: +1:75
+ let _7: [u8; 4]; // in scope 0 at $DIR/issue_99325.rs:+1:51: +1:75
+ let _8: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _9: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _10: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _11: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _12: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _13: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _14: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _16: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _17: core::panicking::AssertKind; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _18: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _19: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _20: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _21: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _22: std::option::Option<std::fmt::Arguments<'_>>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _23: (); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _24: (&&[u8], &&[u8; 4]); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _25: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _26: &[u8]; // in scope 0 at $DIR/issue_99325.rs:+2:16: +2:70
+ let mut _27: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _28: &[u8; 4]; // in scope 0 at $DIR/issue_99325.rs:+2:72: +2:79
+ let _29: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _30: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _31: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _32: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _33: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _34: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _35: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _37: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _38: core::panicking::AssertKind; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _39: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _40: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _41: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _42: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let mut _43: std::option::Option<std::fmt::Arguments<'_>>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ scope 1 {
+ debug left_val => _8; // in scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug right_val => _9; // in scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _15: core::panicking::AssertKind; // in scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ scope 2 {
+ debug kind => _15; // in scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+ }
+ scope 3 {
+ debug left_val => _29; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ debug right_val => _30; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ let _36: core::panicking::AssertKind; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ scope 4 {
+ debug kind => _36; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_3); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_4); // scope 0 at $DIR/issue_99325.rs:+1:16: +1:48
+ _4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb19]; // scope 0 at $DIR/issue_99325.rs:+1:16: +1:48
+ // mir::Constant
+ // + span: $DIR/issue_99325.rs:10:16: 10:46
+ // + user_ty: UserType(0)
+ // + literal: Const { ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}, val: Value(<ZST>) }
+ }
+
+ bb1: {
+ _3 = &_4; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_5); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_6); // scope 0 at $DIR/issue_99325.rs:+1:50: +1:75
+ StorageLive(_7); // scope 0 at $DIR/issue_99325.rs:+1:51: +1:75
+ _7 = [const 65_u8, const 65_u8, const 65_u8, const 65_u8]; // scope 0 at $DIR/issue_99325.rs:+1:51: +1:75
+ _6 = &_7; // scope 0 at $DIR/issue_99325.rs:+1:50: +1:75
+ _5 = &_6; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _2 = (move _3, move _5); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_5); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_3); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ FakeRead(ForMatchedPlace(None), _2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_8); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _8 = (_2.0: &&[u8]); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_9); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _9 = (_2.1: &&[u8; 4]); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_10); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_11); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_12); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _12 = &(*_8); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_13); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _13 = &(*_9); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _11 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _12, move _13) -> [return: bb2, unwind: bb19]; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ // mir::Constant
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ // + literal: Const { ty: for<'a, 'b> fn(&'a &[u8], &'b &[u8; 4]) -> bool {<&[u8] as PartialEq<&[u8; 4]>>::eq}, val: Value(<ZST>) }
+ }
+
+ bb2: {
+ StorageDead(_13); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_12); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _10 = Not(move _11); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_11); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ switchInt(move _10) -> [false: bb4, otherwise: bb3]; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb3: {
+ StorageLive(_15); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _15 = core::panicking::AssertKind::Eq; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ FakeRead(ForLet(None), _15); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_16); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_17); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _17 = move _15; // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_18); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_19); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _19 = &(*_8); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _18 = &(*_19); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_20); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_21); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _21 = &(*_9); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _20 = &(*_21); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_22); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _22 = Option::<Arguments<'_>>::None; // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _16 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _17, move _18, move _20, move _22) -> bb19; // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ // mir::Constant
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ // + literal: Const { ty: for<'a, 'b, 'c> fn(core::panicking::AssertKind, &'a &[u8], &'b &[u8; 4], Option<Arguments<'c>>) -> ! {core::panicking::assert_failed::<&[u8], &[u8; 4]>}, val: Value(<ZST>) }
+ }
+
+ bb4: {
+ goto -> bb7; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb5: {
+ StorageDead(_22); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_20); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_18); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_17); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_21); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_19); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_16); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_15); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ unreachable; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb6: {
+ goto -> bb8; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb7: {
+ _1 = const (); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ goto -> bb8; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb8: {
+ StorageDead(_10); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_9); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_8); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ goto -> bb9; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb9: {
+ StorageDead(_7); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_6); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_4); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_1); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_23); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_24); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_25); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_26); // scope 0 at $DIR/issue_99325.rs:+2:16: +2:70
+ _26 = function_with_bytes::<&*b"AAAA">() -> [return: bb10, unwind: bb19]; // scope 0 at $DIR/issue_99325.rs:+2:16: +2:70
+ // mir::Constant
+ // + span: $DIR/issue_99325.rs:11:16: 11:68
+ // + user_ty: UserType(1)
+ // + literal: Const { ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}, val: Value(<ZST>) }
+ }
+
+ bb10: {
+ _25 = &_26; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_27); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_28); // scope 0 at $DIR/issue_99325.rs:+2:72: +2:79
+ _28 = const b"AAAA"; // scope 0 at $DIR/issue_99325.rs:+2:72: +2:79
+ // mir::Constant
+ // + span: $DIR/issue_99325.rs:11:72: 11:79
+ // + literal: Const { ty: &[u8; 4], val: Value(Scalar(alloc4)) }
+ _27 = &_28; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _24 = (move _25, move _27); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_27); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_25); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ FakeRead(ForMatchedPlace(None), _24); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_29); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _29 = (_24.0: &&[u8]); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_30); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _30 = (_24.1: &&[u8; 4]); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_31); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_33); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _33 = &(*_29); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_34); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _34 = &(*_30); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _32 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _33, move _34) -> [return: bb11, unwind: bb19]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ // mir::Constant
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ // + literal: Const { ty: for<'a, 'b> fn(&'a &[u8], &'b &[u8; 4]) -> bool {<&[u8] as PartialEq<&[u8; 4]>>::eq}, val: Value(<ZST>) }
+ }
+
+ bb11: {
+ StorageDead(_34); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_33); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _31 = Not(move _32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ switchInt(move _31) -> [false: bb13, otherwise: bb12]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb12: {
+ StorageLive(_36); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _36 = core::panicking::AssertKind::Eq; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ FakeRead(ForLet(None), _36); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_37); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_38); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _38 = move _36; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_39); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_40); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _40 = &(*_29); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _39 = &(*_40); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_41); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_42); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _42 = &(*_30); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _41 = &(*_42); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageLive(_43); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _43 = Option::<Arguments<'_>>::None; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _37 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _38, move _39, move _41, move _43) -> bb19; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ // mir::Constant
+ // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ // + literal: Const { ty: for<'a, 'b, 'c> fn(core::panicking::AssertKind, &'a &[u8], &'b &[u8; 4], Option<Arguments<'c>>) -> ! {core::panicking::assert_failed::<&[u8], &[u8; 4]>}, val: Value(<ZST>) }
+ }
+
+ bb13: {
+ goto -> bb16; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb14: {
+ StorageDead(_43); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_41); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_39); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_38); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_42); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_40); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_37); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_36); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ unreachable; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb15: {
+ goto -> bb17; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb16: {
+ _23 = const (); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ goto -> bb17; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb17: {
+ StorageDead(_31); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_30); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_29); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ goto -> bb18; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ }
+
+ bb18: {
+ StorageDead(_28); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_26); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_24); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ StorageDead(_23); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
+ _0 = const (); // scope 0 at $DIR/issue_99325.rs:+0:15: +3:2
+ return; // scope 0 at $DIR/issue_99325.rs:+3:2: +3:2
+ }
+
+ bb19 (cleanup): {
+ resume; // scope 0 at $DIR/issue_99325.rs:+0:1: +3:2
+ }
+}
+
+alloc4 (size: 4, align: 1) {
+ 41 41 41 41 │ AAAA
+}
+++ /dev/null
-// MIR for `main` 0 mir_map
-
-| User Type Annotations
-| 0: user_ty: Canonical { max_universe: U0, variables: [], value: TypeOf(DefId(0:3 ~ issue_99325[8f58]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: Value(Branch([Leaf(0x41), Leaf(0x41), Leaf(0x41), Leaf(0x41)])) }], user_self_ty: None }) }, span: $DIR/issue-99325.rs:10:16: 10:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
-| 1: user_ty: Canonical { max_universe: U0, variables: [], value: TypeOf(DefId(0:3 ~ issue_99325[8f58]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: Unevaluated(UnevaluatedConst { def: WithOptConstParam { did: DefId(0:8 ~ issue_99325[8f58]::main::{constant#1}), const_param_did: Some(DefId(0:4 ~ issue_99325[8f58]::function_with_bytes::BYTES)) }, substs: [] }) }], user_self_ty: None }) }, span: $DIR/issue-99325.rs:11:16: 11:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}
-|
-fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/issue-99325.rs:+0:15: +0:15
- let _1: (); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _2: (&&[u8], &&[u8; 4]); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _3: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _4: &[u8]; // in scope 0 at $DIR/issue-99325.rs:+1:16: +1:48
- let mut _5: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _6: &[u8; 4]; // in scope 0 at $DIR/issue-99325.rs:+1:50: +1:75
- let _7: [u8; 4]; // in scope 0 at $DIR/issue-99325.rs:+1:51: +1:75
- let _8: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _9: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _10: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _11: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _12: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _13: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _14: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _16: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _17: core::panicking::AssertKind; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _18: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _19: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _20: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _21: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _22: std::option::Option<std::fmt::Arguments<'_>>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _23: (); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _24: (&&[u8], &&[u8; 4]); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _25: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _26: &[u8]; // in scope 0 at $DIR/issue-99325.rs:+2:16: +2:70
- let mut _27: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _28: &[u8; 4]; // in scope 0 at $DIR/issue-99325.rs:+2:72: +2:79
- let _29: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _30: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _31: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _32: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _33: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _34: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _35: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _37: !; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _38: core::panicking::AssertKind; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _39: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _40: &&[u8]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _41: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _42: &&[u8; 4]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let mut _43: std::option::Option<std::fmt::Arguments<'_>>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- scope 1 {
- debug left_val => _8; // in scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- debug right_val => _9; // in scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _15: core::panicking::AssertKind; // in scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- scope 2 {
- debug kind => _15; // in scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
- }
- scope 3 {
- debug left_val => _29; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- debug right_val => _30; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- let _36: core::panicking::AssertKind; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- scope 4 {
- debug kind => _36; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_3); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_4); // scope 0 at $DIR/issue-99325.rs:+1:16: +1:48
- _4 = function_with_bytes::<&*b"AAAA">() -> [return: bb1, unwind: bb19]; // scope 0 at $DIR/issue-99325.rs:+1:16: +1:48
- // mir::Constant
- // + span: $DIR/issue-99325.rs:10:16: 10:46
- // + user_ty: UserType(0)
- // + literal: Const { ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}, val: Value(<ZST>) }
- }
-
- bb1: {
- _3 = &_4; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_5); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_6); // scope 0 at $DIR/issue-99325.rs:+1:50: +1:75
- StorageLive(_7); // scope 0 at $DIR/issue-99325.rs:+1:51: +1:75
- _7 = [const 65_u8, const 65_u8, const 65_u8, const 65_u8]; // scope 0 at $DIR/issue-99325.rs:+1:51: +1:75
- _6 = &_7; // scope 0 at $DIR/issue-99325.rs:+1:50: +1:75
- _5 = &_6; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _2 = (move _3, move _5); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_5); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_3); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- FakeRead(ForMatchedPlace(None), _2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_8); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _8 = (_2.0: &&[u8]); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_9); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _9 = (_2.1: &&[u8; 4]); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_10); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_11); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_12); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _12 = &(*_8); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_13); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _13 = &(*_9); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _11 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _12, move _13) -> [return: bb2, unwind: bb19]; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // mir::Constant
- // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: for<'a, 'b> fn(&'a &[u8], &'b &[u8; 4]) -> bool {<&[u8] as PartialEq<&[u8; 4]>>::eq}, val: Value(<ZST>) }
- }
-
- bb2: {
- StorageDead(_13); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_12); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _10 = Not(move _11); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_11); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- switchInt(move _10) -> [false: bb4, otherwise: bb3]; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
-
- bb3: {
- StorageLive(_15); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _15 = core::panicking::AssertKind::Eq; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- FakeRead(ForLet(None), _15); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_16); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_17); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _17 = move _15; // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_18); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_19); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _19 = &(*_8); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _18 = &(*_19); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_20); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_21); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _21 = &(*_9); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _20 = &(*_21); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_22); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _22 = Option::<Arguments<'_>>::None; // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _16 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _17, move _18, move _20, move _22) -> bb19; // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // mir::Constant
- // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: for<'a, 'b, 'c> fn(core::panicking::AssertKind, &'a &[u8], &'b &[u8; 4], Option<Arguments<'c>>) -> ! {core::panicking::assert_failed::<&[u8], &[u8; 4]>}, val: Value(<ZST>) }
- }
-
- bb4: {
- goto -> bb7; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
-
- bb5: {
- StorageDead(_22); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_20); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_18); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_17); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_21); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_19); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_16); // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_15); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- unreachable; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
-
- bb6: {
- goto -> bb8; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
-
- bb7: {
- _1 = const (); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- goto -> bb8; // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
-
- bb8: {
- StorageDead(_10); // scope 1 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_9); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_8); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- goto -> bb9; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
-
- bb9: {
- StorageDead(_7); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_6); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_4); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_1); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_23); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_24); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_25); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_26); // scope 0 at $DIR/issue-99325.rs:+2:16: +2:70
- _26 = function_with_bytes::<&*b"AAAA">() -> [return: bb10, unwind: bb19]; // scope 0 at $DIR/issue-99325.rs:+2:16: +2:70
- // mir::Constant
- // + span: $DIR/issue-99325.rs:11:16: 11:68
- // + user_ty: UserType(1)
- // + literal: Const { ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">}, val: Value(<ZST>) }
- }
-
- bb10: {
- _25 = &_26; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_27); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_28); // scope 0 at $DIR/issue-99325.rs:+2:72: +2:79
- _28 = const b"AAAA"; // scope 0 at $DIR/issue-99325.rs:+2:72: +2:79
- // mir::Constant
- // + span: $DIR/issue-99325.rs:11:72: 11:79
- // + literal: Const { ty: &[u8; 4], val: Value(Scalar(alloc4)) }
- _27 = &_28; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _24 = (move _25, move _27); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_27); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_25); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- FakeRead(ForMatchedPlace(None), _24); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_29); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _29 = (_24.0: &&[u8]); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_30); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _30 = (_24.1: &&[u8; 4]); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_31); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_33); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _33 = &(*_29); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_34); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _34 = &(*_30); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _32 = <&[u8] as PartialEq<&[u8; 4]>>::eq(move _33, move _34) -> [return: bb11, unwind: bb19]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // mir::Constant
- // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: for<'a, 'b> fn(&'a &[u8], &'b &[u8; 4]) -> bool {<&[u8] as PartialEq<&[u8; 4]>>::eq}, val: Value(<ZST>) }
- }
-
- bb11: {
- StorageDead(_34); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_33); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _31 = Not(move _32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- switchInt(move _31) -> [false: bb13, otherwise: bb12]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
-
- bb12: {
- StorageLive(_36); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _36 = core::panicking::AssertKind::Eq; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- FakeRead(ForLet(None), _36); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_37); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_38); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _38 = move _36; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_39); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_40); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _40 = &(*_29); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _39 = &(*_40); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_41); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_42); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _42 = &(*_30); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _41 = &(*_42); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageLive(_43); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _43 = Option::<Arguments<'_>>::None; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _37 = core::panicking::assert_failed::<&[u8], &[u8; 4]>(move _38, move _39, move _41, move _43) -> bb19; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // mir::Constant
- // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL
- // + literal: Const { ty: for<'a, 'b, 'c> fn(core::panicking::AssertKind, &'a &[u8], &'b &[u8; 4], Option<Arguments<'c>>) -> ! {core::panicking::assert_failed::<&[u8], &[u8; 4]>}, val: Value(<ZST>) }
- }
-
- bb13: {
- goto -> bb16; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
-
- bb14: {
- StorageDead(_43); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_41); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_39); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_38); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_42); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_40); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_37); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_36); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- unreachable; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
-
- bb15: {
- goto -> bb17; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
-
- bb16: {
- _23 = const (); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- goto -> bb17; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
-
- bb17: {
- StorageDead(_31); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_30); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_29); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- goto -> bb18; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- }
-
- bb18: {
- StorageDead(_28); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_26); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_24); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- StorageDead(_23); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- _0 = const (); // scope 0 at $DIR/issue-99325.rs:+0:15: +3:2
- return; // scope 0 at $DIR/issue-99325.rs:+3:2: +3:2
- }
-
- bb19 (cleanup): {
- resume; // scope 0 at $DIR/issue-99325.rs:+0:1: +3:2
- }
-}
-
-alloc4 (size: 4, align: 1) {
- 41 41 41 41 │ AAAA
-}
--- /dev/null
+#![feature(adt_const_params)]
+#![allow(incomplete_features)]
+
+pub fn function_with_bytes<const BYTES: &'static [u8; 4]>() -> &'static [u8] {
+ BYTES
+}
+
+// EMIT_MIR issue_99325.main.built.after.mir
+pub fn main() {
+ assert_eq!(function_with_bytes::<b"AAAA">(), &[0x41, 0x41, 0x41, 0x41]);
+ assert_eq!(function_with_bytes::<{ &[0x41, 0x41, 0x41, 0x41] }>(), b"AAAA");
+}
+++ /dev/null
-// This test is a mirror of codegen/issue-59352.rs.
-// The LLVM inliner doesn't inline `char::method::is_digit()` and so it doesn't recognize this case
-// as effectively `if x.is_some() { x.unwrap() } else { 0 }`.
-//
-// Currently, the MIR optimizer isn't capable of removing the unreachable panic in this test case.
-// Once the optimizer can do that, this test case will need to be updated and codegen/issue-59352.rs
-// removed.
-
-// EMIT_MIR issue_59352.num_to_digit.PreCodegen.after.mir
-// compile-flags: -Z mir-opt-level=3 -Z span_free_formats
-
-pub fn num_to_digit(num: char) -> u32 {
- // CHECK-NOT: panic
- if num.is_digit(8) { num.to_digit(8).unwrap() } else { 0 }
-}
-
-pub fn main() {
- num_to_digit('2');
-}
+++ /dev/null
-// EMIT_MIR issue_75439.foo.MatchBranchSimplification.diff
-
-use std::mem::transmute;
-
-pub fn foo(bytes: [u8; 16]) -> Option<[u8; 4]> {
- // big endian `u32`s
- let dwords: [u32; 4] = unsafe { transmute(bytes) };
- const FF: u32 = 0x0000_ffff_u32.to_be();
- if let [0, 0, 0 | FF, ip] = dwords {
- Some(unsafe { transmute(ip) })
- } else {
- None
- }
-}
-
-fn main() {
- let _ = foo([0; 16]);
-}
// MIR for `num_to_digit` after PreCodegen
fn num_to_digit(_1: char) -> u32 {
- debug num => _1; // in scope 0 at $DIR/issue-59352.rs:+0:21: +0:24
- let mut _0: u32; // return place in scope 0 at $DIR/issue-59352.rs:+0:35: +0:38
- let mut _2: char; // in scope 0 at $DIR/issue-59352.rs:+2:8: +2:11
- let mut _3: std::option::Option<u32>; // in scope 0 at $DIR/issue-59352.rs:+2:26: +2:41
- let mut _4: char; // in scope 0 at $DIR/issue-59352.rs:+2:26: +2:29
- let mut _5: u32; // in scope 0 at $DIR/issue-59352.rs:+2:8: +2:23
+ debug num => _1; // in scope 0 at $DIR/issue_59352.rs:+0:21: +0:24
+ let mut _0: u32; // return place in scope 0 at $DIR/issue_59352.rs:+0:35: +0:38
+ let mut _2: char; // in scope 0 at $DIR/issue_59352.rs:+2:8: +2:11
+ let mut _3: std::option::Option<u32>; // in scope 0 at $DIR/issue_59352.rs:+2:26: +2:41
+ let mut _4: char; // in scope 0 at $DIR/issue_59352.rs:+2:26: +2:29
+ let mut _5: u32; // in scope 0 at $DIR/issue_59352.rs:+2:8: +2:23
let mut _12: isize; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
- scope 1 (inlined char::methods::<impl char>::is_digit) { // at $DIR/issue-59352.rs:14:8: 14:23
+ scope 1 (inlined char::methods::<impl char>::is_digit) { // at $DIR/issue_59352.rs:14:8: 14:23
debug self => _2; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
debug radix => _5; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
let mut _6: &std::option::Option<u32>; // in scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
let mut _9: isize; // in scope 2 at $SRC_DIR/core/src/option.rs:LL:COL
}
}
- scope 3 (inlined #[track_caller] Option::<u32>::unwrap) { // at $DIR/issue-59352.rs:14:26: 14:50
+ scope 3 (inlined #[track_caller] Option::<u32>::unwrap) { // at $DIR/issue_59352.rs:14:26: 14:50
debug self => _3; // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
let mut _10: isize; // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
let mut _11: !; // in scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
}
bb0: {
- StorageLive(_2); // scope 0 at $DIR/issue-59352.rs:+2:8: +2:11
- _2 = _1; // scope 0 at $DIR/issue-59352.rs:+2:8: +2:11
- StorageLive(_5); // scope 0 at $DIR/issue-59352.rs:+2:8: +2:23
+ StorageLive(_2); // scope 0 at $DIR/issue_59352.rs:+2:8: +2:11
+ _2 = _1; // scope 0 at $DIR/issue_59352.rs:+2:8: +2:11
+ StorageLive(_5); // scope 0 at $DIR/issue_59352.rs:+2:8: +2:23
StorageLive(_6); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
StorageLive(_7); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
StorageLive(_8); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
}
bb1: {
- StorageDead(_12); // scope 0 at $DIR/issue-59352.rs:+2:8: +2:23
- StorageLive(_3); // scope 0 at $DIR/issue-59352.rs:+2:26: +2:41
- StorageLive(_4); // scope 0 at $DIR/issue-59352.rs:+2:26: +2:29
- _4 = _1; // scope 0 at $DIR/issue-59352.rs:+2:26: +2:29
- _3 = char::methods::<impl char>::to_digit(move _4, const 8_u32) -> bb2; // scope 0 at $DIR/issue-59352.rs:+2:26: +2:41
+ StorageDead(_12); // scope 0 at $DIR/issue_59352.rs:+2:8: +2:23
+ StorageLive(_3); // scope 0 at $DIR/issue_59352.rs:+2:26: +2:41
+ StorageLive(_4); // scope 0 at $DIR/issue_59352.rs:+2:26: +2:29
+ _4 = _1; // scope 0 at $DIR/issue_59352.rs:+2:26: +2:29
+ _3 = char::methods::<impl char>::to_digit(move _4, const 8_u32) -> bb2; // scope 0 at $DIR/issue_59352.rs:+2:26: +2:41
// mir::Constant
- // + span: $DIR/issue-59352.rs:14:30: 14:38
+ // + span: $DIR/issue_59352.rs:14:30: 14:38
// + literal: Const { ty: fn(char, u32) -> Option<u32> {char::methods::<impl char>::to_digit}, val: Value(<ZST>) }
}
bb2: {
- StorageDead(_4); // scope 0 at $DIR/issue-59352.rs:+2:40: +2:41
+ StorageDead(_4); // scope 0 at $DIR/issue_59352.rs:+2:40: +2:41
_10 = discriminant(_3); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
switchInt(move _10) -> [0_isize: bb6, 1_isize: bb8, otherwise: bb7]; // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
}
bb3: {
- StorageDead(_12); // scope 0 at $DIR/issue-59352.rs:+2:8: +2:23
- _0 = const 0_u32; // scope 0 at $DIR/issue-59352.rs:+2:60: +2:61
- goto -> bb4; // scope 0 at $DIR/issue-59352.rs:+2:5: +2:63
+ StorageDead(_12); // scope 0 at $DIR/issue_59352.rs:+2:8: +2:23
+ _0 = const 0_u32; // scope 0 at $DIR/issue_59352.rs:+2:60: +2:61
+ goto -> bb4; // scope 0 at $DIR/issue_59352.rs:+2:5: +2:63
}
bb4: {
- return; // scope 0 at $DIR/issue-59352.rs:+3:2: +3:2
+ return; // scope 0 at $DIR/issue_59352.rs:+3:2: +3:2
}
bb5: {
_12 = move _9; // scope 2 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageDead(_6); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
StorageDead(_7); // scope 1 at $SRC_DIR/core/src/char/methods.rs:LL:COL
- StorageDead(_5); // scope 0 at $DIR/issue-59352.rs:+2:8: +2:23
- StorageDead(_2); // scope 0 at $DIR/issue-59352.rs:+2:22: +2:23
- switchInt(move _12) -> [1_isize: bb1, otherwise: bb3]; // scope 0 at $DIR/issue-59352.rs:+2:8: +2:23
+ StorageDead(_5); // scope 0 at $DIR/issue_59352.rs:+2:8: +2:23
+ StorageDead(_2); // scope 0 at $DIR/issue_59352.rs:+2:22: +2:23
+ switchInt(move _12) -> [1_isize: bb1, otherwise: bb3]; // scope 0 at $DIR/issue_59352.rs:+2:8: +2:23
}
bb6: {
bb8: {
_0 = move ((_3 as Some).0: u32); // scope 3 at $SRC_DIR/core/src/option.rs:LL:COL
- StorageDead(_3); // scope 0 at $DIR/issue-59352.rs:+2:49: +2:50
- goto -> bb4; // scope 0 at $DIR/issue-59352.rs:+2:5: +2:63
+ StorageDead(_3); // scope 0 at $DIR/issue_59352.rs:+2:49: +2:50
+ goto -> bb4; // scope 0 at $DIR/issue_59352.rs:+2:5: +2:63
}
}
--- /dev/null
+// This test is a mirror of codegen/issue-59352.rs.
+// The LLVM inliner doesn't inline `char::method::is_digit()` and so it doesn't recognize this case
+// as effectively `if x.is_some() { x.unwrap() } else { 0 }`.
+//
+// Currently, the MIR optimizer isn't capable of removing the unreachable panic in this test case.
+// Once the optimizer can do that, this test case will need to be updated and codegen/issue-59352.rs
+// removed.
+
+// EMIT_MIR issue_59352.num_to_digit.PreCodegen.after.mir
+// compile-flags: -Z mir-opt-level=3 -Z span_free_formats
+
+pub fn num_to_digit(num: char) -> u32 {
+ // CHECK-NOT: panic
+ if num.is_digit(8) { num.to_digit(8).unwrap() } else { 0 }
+}
+
+pub fn main() {
+ num_to_digit('2');
+}
+ // MIR for `foo` after MatchBranchSimplification
fn foo(_1: [u8; 16]) -> Option<[u8; 4]> {
- debug bytes => _1; // in scope 0 at $DIR/issue-75439.rs:+0:12: +0:17
- let mut _0: std::option::Option<[u8; 4]>; // return place in scope 0 at $DIR/issue-75439.rs:+0:32: +0:47
- let _2: [u32; 4]; // in scope 0 at $DIR/issue-75439.rs:+2:9: +2:15
- let mut _3: [u8; 16]; // in scope 0 at $DIR/issue-75439.rs:+2:47: +2:52
- let mut _5: [u8; 4]; // in scope 0 at $DIR/issue-75439.rs:+5:14: +5:38
- let mut _6: u32; // in scope 0 at $DIR/issue-75439.rs:+5:33: +5:35
+ debug bytes => _1; // in scope 0 at $DIR/issue_75439.rs:+0:12: +0:17
+ let mut _0: std::option::Option<[u8; 4]>; // return place in scope 0 at $DIR/issue_75439.rs:+0:32: +0:47
+ let _2: [u32; 4]; // in scope 0 at $DIR/issue_75439.rs:+2:9: +2:15
+ let mut _3: [u8; 16]; // in scope 0 at $DIR/issue_75439.rs:+2:47: +2:52
+ let mut _5: [u8; 4]; // in scope 0 at $DIR/issue_75439.rs:+5:14: +5:38
+ let mut _6: u32; // in scope 0 at $DIR/issue_75439.rs:+5:33: +5:35
scope 1 {
- debug dwords => _2; // in scope 1 at $DIR/issue-75439.rs:+2:9: +2:15
+ debug dwords => _2; // in scope 1 at $DIR/issue_75439.rs:+2:9: +2:15
scope 3 {
- debug ip => _4; // in scope 3 at $DIR/issue-75439.rs:+4:27: +4:29
- let _4: u32; // in scope 3 at $DIR/issue-75439.rs:+4:27: +4:29
+ debug ip => _4; // in scope 3 at $DIR/issue_75439.rs:+4:27: +4:29
+ let _4: u32; // in scope 3 at $DIR/issue_75439.rs:+4:27: +4:29
scope 4 {
}
}
}
bb0: {
- StorageLive(_2); // scope 0 at $DIR/issue-75439.rs:+2:9: +2:15
- StorageLive(_3); // scope 2 at $DIR/issue-75439.rs:+2:47: +2:52
- _3 = _1; // scope 2 at $DIR/issue-75439.rs:+2:47: +2:52
- _2 = transmute::<[u8; 16], [u32; 4]>(move _3) -> bb1; // scope 2 at $DIR/issue-75439.rs:+2:37: +2:53
+ StorageLive(_2); // scope 0 at $DIR/issue_75439.rs:+2:9: +2:15
+ StorageLive(_3); // scope 2 at $DIR/issue_75439.rs:+2:47: +2:52
+ _3 = _1; // scope 2 at $DIR/issue_75439.rs:+2:47: +2:52
+ _2 = transmute::<[u8; 16], [u32; 4]>(move _3) -> bb1; // scope 2 at $DIR/issue_75439.rs:+2:37: +2:53
// mir::Constant
- // + span: $DIR/issue-75439.rs:7:37: 7:46
+ // + span: $DIR/issue_75439.rs:7:37: 7:46
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn([u8; 16]) -> [u32; 4] {transmute::<[u8; 16], [u32; 4]>}, val: Value(<ZST>) }
}
bb1: {
- StorageDead(_3); // scope 2 at $DIR/issue-75439.rs:+2:52: +2:53
- switchInt(_2[0 of 4]) -> [0_u32: bb2, otherwise: bb8]; // scope 3 at $DIR/issue-75439.rs:+4:12: +4:30
+ StorageDead(_3); // scope 2 at $DIR/issue_75439.rs:+2:52: +2:53
+ switchInt(_2[0 of 4]) -> [0_u32: bb2, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
}
bb2: {
- switchInt(_2[1 of 4]) -> [0_u32: bb3, otherwise: bb8]; // scope 3 at $DIR/issue-75439.rs:+4:12: +4:30
+ switchInt(_2[1 of 4]) -> [0_u32: bb3, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
}
bb3: {
- switchInt(_2[2 of 4]) -> [0_u32: bb5, 4294901760_u32: bb6, otherwise: bb8]; // scope 3 at $DIR/issue-75439.rs:+4:12: +4:30
+ switchInt(_2[2 of 4]) -> [0_u32: bb5, 4294901760_u32: bb6, otherwise: bb8]; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
}
bb4: {
- StorageLive(_5); // scope 3 at $DIR/issue-75439.rs:+5:14: +5:38
- StorageLive(_6); // scope 4 at $DIR/issue-75439.rs:+5:33: +5:35
- _6 = _4; // scope 4 at $DIR/issue-75439.rs:+5:33: +5:35
- _5 = transmute::<u32, [u8; 4]>(move _6) -> bb7; // scope 4 at $DIR/issue-75439.rs:+5:23: +5:36
+ StorageLive(_5); // scope 3 at $DIR/issue_75439.rs:+5:14: +5:38
+ StorageLive(_6); // scope 4 at $DIR/issue_75439.rs:+5:33: +5:35
+ _6 = _4; // scope 4 at $DIR/issue_75439.rs:+5:33: +5:35
+ _5 = transmute::<u32, [u8; 4]>(move _6) -> bb7; // scope 4 at $DIR/issue_75439.rs:+5:23: +5:36
// mir::Constant
- // + span: $DIR/issue-75439.rs:10:23: 10:32
+ // + span: $DIR/issue_75439.rs:10:23: 10:32
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) -> [u8; 4] {transmute::<u32, [u8; 4]>}, val: Value(<ZST>) }
}
bb5: {
- StorageLive(_4); // scope 3 at $DIR/issue-75439.rs:+4:27: +4:29
- _4 = _2[3 of 4]; // scope 3 at $DIR/issue-75439.rs:+4:27: +4:29
- goto -> bb4; // scope 3 at $DIR/issue-75439.rs:+4:12: +4:30
+ StorageLive(_4); // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29
+ _4 = _2[3 of 4]; // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29
+ goto -> bb4; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
}
bb6: {
- StorageLive(_4); // scope 3 at $DIR/issue-75439.rs:+4:27: +4:29
- _4 = _2[3 of 4]; // scope 3 at $DIR/issue-75439.rs:+4:27: +4:29
- goto -> bb4; // scope 3 at $DIR/issue-75439.rs:+4:12: +4:30
+ StorageLive(_4); // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29
+ _4 = _2[3 of 4]; // scope 3 at $DIR/issue_75439.rs:+4:27: +4:29
+ goto -> bb4; // scope 3 at $DIR/issue_75439.rs:+4:12: +4:30
}
bb7: {
- StorageDead(_6); // scope 4 at $DIR/issue-75439.rs:+5:35: +5:36
- Deinit(_0); // scope 3 at $DIR/issue-75439.rs:+5:9: +5:39
- ((_0 as Some).0: [u8; 4]) = move _5; // scope 3 at $DIR/issue-75439.rs:+5:9: +5:39
- discriminant(_0) = 1; // scope 3 at $DIR/issue-75439.rs:+5:9: +5:39
- StorageDead(_5); // scope 3 at $DIR/issue-75439.rs:+5:38: +5:39
- StorageDead(_4); // scope 1 at $DIR/issue-75439.rs:+6:5: +6:6
- goto -> bb9; // scope 1 at $DIR/issue-75439.rs:+4:5: +8:6
+ StorageDead(_6); // scope 4 at $DIR/issue_75439.rs:+5:35: +5:36
+ Deinit(_0); // scope 3 at $DIR/issue_75439.rs:+5:9: +5:39
+ ((_0 as Some).0: [u8; 4]) = move _5; // scope 3 at $DIR/issue_75439.rs:+5:9: +5:39
+ discriminant(_0) = 1; // scope 3 at $DIR/issue_75439.rs:+5:9: +5:39
+ StorageDead(_5); // scope 3 at $DIR/issue_75439.rs:+5:38: +5:39
+ StorageDead(_4); // scope 1 at $DIR/issue_75439.rs:+6:5: +6:6
+ goto -> bb9; // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6
}
bb8: {
- Deinit(_0); // scope 1 at $DIR/issue-75439.rs:+7:9: +7:13
- discriminant(_0) = 0; // scope 1 at $DIR/issue-75439.rs:+7:9: +7:13
- goto -> bb9; // scope 1 at $DIR/issue-75439.rs:+4:5: +8:6
+ Deinit(_0); // scope 1 at $DIR/issue_75439.rs:+7:9: +7:13
+ discriminant(_0) = 0; // scope 1 at $DIR/issue_75439.rs:+7:9: +7:13
+ goto -> bb9; // scope 1 at $DIR/issue_75439.rs:+4:5: +8:6
}
bb9: {
- StorageDead(_2); // scope 0 at $DIR/issue-75439.rs:+9:1: +9:2
- return; // scope 0 at $DIR/issue-75439.rs:+9:2: +9:2
+ StorageDead(_2); // scope 0 at $DIR/issue_75439.rs:+9:1: +9:2
+ return; // scope 0 at $DIR/issue_75439.rs:+9:2: +9:2
}
}
--- /dev/null
+// EMIT_MIR issue_75439.foo.MatchBranchSimplification.diff
+
+use std::mem::transmute;
+
+pub fn foo(bytes: [u8; 16]) -> Option<[u8; 4]> {
+ // big endian `u32`s
+ let dwords: [u32; 4] = unsafe { transmute(bytes) };
+ const FF: u32 = 0x0000_ffff_u32.to_be();
+ if let [0, 0, 0 | FF, ip] = dwords {
+ Some(unsafe { transmute(ip) })
+ } else {
+ None
+ }
+}
+
+fn main() {
+ let _ = foo([0; 16]);
+}
+++ /dev/null
-// ignore-wasm32-bare compiled with panic=abort by default
-// Test that StorageDead and Drops are generated properly for bindings in
-// matches:
-// * The MIR should only contain a single drop of `s` and `t`: at the end
-// of their respective arms.
-// * StorageDead and StorageLive statements are correctly matched up on
-// non-unwind paths.
-// * The visibility scopes of the match arms should be disjoint, and contain.
-// all of the bindings for that scope.
-// * No drop flags are used.
-
-// EMIT_MIR match_arm_scopes.complicated_match SimplifyCfg-initial.after ElaborateDrops.after
-fn complicated_match(cond: bool, items: (bool, bool, String)) -> i32 {
- match items {
- (false, a, s) | (a, false, s) if if cond { return 3 } else { a } => 1,
- (true, b, t) | (false, b, t) => 2,
- }
-}
-
-const CASES: &[(bool, bool, bool, i32)] = &[
- (false, false, false, 2),
- (false, false, true, 1),
- (false, true, false, 1),
- (false, true, true, 2),
- (true, false, false, 3),
- (true, false, true, 3),
- (true, true, false, 3),
- (true, true, true, 2),
-];
-
-fn main() {
- for &(cond, items_1, items_2, result) in CASES {
- assert_eq!(complicated_match(cond, (items_1, items_2, String::new())), result,);
- }
-}
+ // MIR for `complicated_match` after ElaborateDrops
fn complicated_match(_1: bool, _2: (bool, bool, String)) -> i32 {
- debug cond => _1; // in scope 0 at $DIR/match-arm-scopes.rs:+0:22: +0:26
- debug items => _2; // in scope 0 at $DIR/match-arm-scopes.rs:+0:34: +0:39
- let mut _0: i32; // return place in scope 0 at $DIR/match-arm-scopes.rs:+0:66: +0:69
- let mut _3: &bool; // in scope 0 at $DIR/match-arm-scopes.rs:+1:11: +1:16
- let mut _4: &bool; // in scope 0 at $DIR/match-arm-scopes.rs:+1:11: +1:16
- let _5: bool; // in scope 0 at $DIR/match-arm-scopes.rs:+2:17: +2:18
- let _6: &bool; // in scope 0 at $DIR/match-arm-scopes.rs:+2:17: +2:18
- let _7: std::string::String; // in scope 0 at $DIR/match-arm-scopes.rs:+2:20: +2:21
- let _8: &std::string::String; // in scope 0 at $DIR/match-arm-scopes.rs:+2:20: +2:21
- let mut _9: bool; // in scope 0 at $DIR/match-arm-scopes.rs:+2:42: +2:73
- let mut _10: bool; // in scope 0 at $DIR/match-arm-scopes.rs:+2:45: +2:49
- let mut _11: !; // in scope 0 at $DIR/match-arm-scopes.rs:+2:52: +2:60
- let mut _12: bool; // in scope 0 at $DIR/match-arm-scopes.rs:+2:42: +2:73
- let mut _13: bool; // in scope 0 at $DIR/match-arm-scopes.rs:+2:45: +2:49
- let mut _14: !; // in scope 0 at $DIR/match-arm-scopes.rs:+2:52: +2:60
- let _15: bool; // in scope 0 at $DIR/match-arm-scopes.rs:+3:16: +3:17
- let _16: std::string::String; // in scope 0 at $DIR/match-arm-scopes.rs:+3:19: +3:20
+ debug cond => _1; // in scope 0 at $DIR/match_arm_scopes.rs:+0:22: +0:26
+ debug items => _2; // in scope 0 at $DIR/match_arm_scopes.rs:+0:34: +0:39
+ let mut _0: i32; // return place in scope 0 at $DIR/match_arm_scopes.rs:+0:66: +0:69
+ let mut _3: &bool; // in scope 0 at $DIR/match_arm_scopes.rs:+1:11: +1:16
+ let mut _4: &bool; // in scope 0 at $DIR/match_arm_scopes.rs:+1:11: +1:16
+ let _5: bool; // in scope 0 at $DIR/match_arm_scopes.rs:+2:17: +2:18
+ let _6: &bool; // in scope 0 at $DIR/match_arm_scopes.rs:+2:17: +2:18
+ let _7: std::string::String; // in scope 0 at $DIR/match_arm_scopes.rs:+2:20: +2:21
+ let _8: &std::string::String; // in scope 0 at $DIR/match_arm_scopes.rs:+2:20: +2:21
+ let mut _9: bool; // in scope 0 at $DIR/match_arm_scopes.rs:+2:42: +2:73
+ let mut _10: bool; // in scope 0 at $DIR/match_arm_scopes.rs:+2:45: +2:49
+ let mut _11: !; // in scope 0 at $DIR/match_arm_scopes.rs:+2:52: +2:60
+ let mut _12: bool; // in scope 0 at $DIR/match_arm_scopes.rs:+2:42: +2:73
+ let mut _13: bool; // in scope 0 at $DIR/match_arm_scopes.rs:+2:45: +2:49
+ let mut _14: !; // in scope 0 at $DIR/match_arm_scopes.rs:+2:52: +2:60
+ let _15: bool; // in scope 0 at $DIR/match_arm_scopes.rs:+3:16: +3:17
+ let _16: std::string::String; // in scope 0 at $DIR/match_arm_scopes.rs:+3:19: +3:20
scope 1 {
- debug a => _5; // in scope 1 at $DIR/match-arm-scopes.rs:+2:17: +2:18
- debug a => _6; // in scope 1 at $DIR/match-arm-scopes.rs:+2:17: +2:18
- debug s => _7; // in scope 1 at $DIR/match-arm-scopes.rs:+2:20: +2:21
- debug s => _8; // in scope 1 at $DIR/match-arm-scopes.rs:+2:20: +2:21
+ debug a => _5; // in scope 1 at $DIR/match_arm_scopes.rs:+2:17: +2:18
+ debug a => _6; // in scope 1 at $DIR/match_arm_scopes.rs:+2:17: +2:18
+ debug s => _7; // in scope 1 at $DIR/match_arm_scopes.rs:+2:20: +2:21
+ debug s => _8; // in scope 1 at $DIR/match_arm_scopes.rs:+2:20: +2:21
}
scope 2 {
- debug b => _15; // in scope 2 at $DIR/match-arm-scopes.rs:+3:16: +3:17
- debug t => _16; // in scope 2 at $DIR/match-arm-scopes.rs:+3:19: +3:20
+ debug b => _15; // in scope 2 at $DIR/match_arm_scopes.rs:+3:16: +3:17
+ debug t => _16; // in scope 2 at $DIR/match_arm_scopes.rs:+3:19: +3:20
}
bb0: {
-- FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match-arm-scopes.rs:+1:11: +1:16
-- switchInt((_2.0: bool)) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +1:16
-+ switchInt((_2.0: bool)) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +1:16
+- FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match_arm_scopes.rs:+1:11: +1:16
+- switchInt((_2.0: bool)) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/match_arm_scopes.rs:+1:5: +1:16
++ switchInt((_2.0: bool)) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/match_arm_scopes.rs:+1:5: +1:16
}
bb1: {
-- falseEdge -> [real: bb8, imaginary: bb3]; // scope 0 at $DIR/match-arm-scopes.rs:+2:9: +2:22
-+ switchInt((_2.1: bool)) -> [false: bb10, otherwise: bb2]; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +1:16
+- falseEdge -> [real: bb8, imaginary: bb3]; // scope 0 at $DIR/match_arm_scopes.rs:+2:9: +2:22
++ switchInt((_2.1: bool)) -> [false: bb10, otherwise: bb2]; // scope 0 at $DIR/match_arm_scopes.rs:+1:5: +1:16
}
bb2: {
-- switchInt((_2.1: bool)) -> [false: bb3, otherwise: bb4]; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +1:16
-+ switchInt((_2.0: bool)) -> [false: bb3, otherwise: bb17]; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +1:16
+- switchInt((_2.1: bool)) -> [false: bb3, otherwise: bb4]; // scope 0 at $DIR/match_arm_scopes.rs:+1:5: +1:16
++ switchInt((_2.0: bool)) -> [false: bb3, otherwise: bb17]; // scope 0 at $DIR/match_arm_scopes.rs:+1:5: +1:16
}
bb3: {
-- falseEdge -> [real: bb13, imaginary: bb5]; // scope 0 at $DIR/match-arm-scopes.rs:+2:25: +2:38
+- falseEdge -> [real: bb13, imaginary: bb5]; // scope 0 at $DIR/match_arm_scopes.rs:+2:25: +2:38
- }
-
- bb4: {
-- switchInt((_2.0: bool)) -> [false: bb6, otherwise: bb5]; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +1:16
+- switchInt((_2.0: bool)) -> [false: bb6, otherwise: bb5]; // scope 0 at $DIR/match_arm_scopes.rs:+1:5: +1:16
- }
-
- bb5: {
-- falseEdge -> [real: bb20, imaginary: bb6]; // scope 0 at $DIR/match-arm-scopes.rs:+3:9: +3:21
+- falseEdge -> [real: bb20, imaginary: bb6]; // scope 0 at $DIR/match_arm_scopes.rs:+3:9: +3:21
- }
-
- bb6: {
- StorageLive(_15); // scope 0 at $DIR/match-arm-scopes.rs:+3:32: +3:33
- _15 = (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:+3:32: +3:33
- StorageLive(_16); // scope 0 at $DIR/match-arm-scopes.rs:+3:35: +3:36
- _16 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:+3:35: +3:36
-- goto -> bb19; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +4:6
-+ goto -> bb16; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +4:6
+ StorageLive(_15); // scope 0 at $DIR/match_arm_scopes.rs:+3:32: +3:33
+ _15 = (_2.1: bool); // scope 0 at $DIR/match_arm_scopes.rs:+3:32: +3:33
+ StorageLive(_16); // scope 0 at $DIR/match_arm_scopes.rs:+3:35: +3:36
+ _16 = move (_2.2: std::string::String); // scope 0 at $DIR/match_arm_scopes.rs:+3:35: +3:36
+- goto -> bb19; // scope 0 at $DIR/match_arm_scopes.rs:+1:5: +4:6
++ goto -> bb16; // scope 0 at $DIR/match_arm_scopes.rs:+1:5: +4:6
}
- bb7: {
+ bb4: {
- _0 = const 1_i32; // scope 1 at $DIR/match-arm-scopes.rs:+2:77: +2:78
-- drop(_7) -> [return: bb18, unwind: bb25]; // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78
-+ drop(_7) -> [return: bb15, unwind: bb22]; // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78
+ _0 = const 1_i32; // scope 1 at $DIR/match_arm_scopes.rs:+2:77: +2:78
+- drop(_7) -> [return: bb18, unwind: bb25]; // scope 0 at $DIR/match_arm_scopes.rs:+2:77: +2:78
++ drop(_7) -> [return: bb15, unwind: bb22]; // scope 0 at $DIR/match_arm_scopes.rs:+2:77: +2:78
}
- bb8: {
+ bb5: {
- StorageLive(_6); // scope 0 at $DIR/match-arm-scopes.rs:+2:17: +2:18
- _6 = &(_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:+2:17: +2:18
- StorageLive(_8); // scope 0 at $DIR/match-arm-scopes.rs:+2:20: +2:21
- _8 = &(_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:+2:20: +2:21
-- _3 = &shallow (_2.0: bool); // scope 0 at $DIR/match-arm-scopes.rs:+1:11: +1:16
-- _4 = &shallow (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:+1:11: +1:16
- StorageLive(_9); // scope 0 at $DIR/match-arm-scopes.rs:+2:42: +2:73
- StorageLive(_10); // scope 0 at $DIR/match-arm-scopes.rs:+2:45: +2:49
- _10 = _1; // scope 0 at $DIR/match-arm-scopes.rs:+2:45: +2:49
-- switchInt(move _10) -> [false: bb10, otherwise: bb9]; // scope 0 at $DIR/match-arm-scopes.rs:+2:45: +2:49
-+ switchInt(move _10) -> [false: bb7, otherwise: bb6]; // scope 0 at $DIR/match-arm-scopes.rs:+2:45: +2:49
+ StorageLive(_6); // scope 0 at $DIR/match_arm_scopes.rs:+2:17: +2:18
+ _6 = &(_2.1: bool); // scope 0 at $DIR/match_arm_scopes.rs:+2:17: +2:18
+ StorageLive(_8); // scope 0 at $DIR/match_arm_scopes.rs:+2:20: +2:21
+ _8 = &(_2.2: std::string::String); // scope 0 at $DIR/match_arm_scopes.rs:+2:20: +2:21
+- _3 = &shallow (_2.0: bool); // scope 0 at $DIR/match_arm_scopes.rs:+1:11: +1:16
+- _4 = &shallow (_2.1: bool); // scope 0 at $DIR/match_arm_scopes.rs:+1:11: +1:16
+ StorageLive(_9); // scope 0 at $DIR/match_arm_scopes.rs:+2:42: +2:73
+ StorageLive(_10); // scope 0 at $DIR/match_arm_scopes.rs:+2:45: +2:49
+ _10 = _1; // scope 0 at $DIR/match_arm_scopes.rs:+2:45: +2:49
+- switchInt(move _10) -> [false: bb10, otherwise: bb9]; // scope 0 at $DIR/match_arm_scopes.rs:+2:45: +2:49
++ switchInt(move _10) -> [false: bb7, otherwise: bb6]; // scope 0 at $DIR/match_arm_scopes.rs:+2:45: +2:49
}
- bb9: {
+ bb6: {
- _0 = const 3_i32; // scope 0 at $DIR/match-arm-scopes.rs:+2:59: +2:60
- StorageDead(_10); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73
- StorageDead(_9); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73
+ _0 = const 3_i32; // scope 0 at $DIR/match_arm_scopes.rs:+2:59: +2:60
+ StorageDead(_10); // scope 0 at $DIR/match_arm_scopes.rs:+2:72: +2:73
+ StorageDead(_9); // scope 0 at $DIR/match_arm_scopes.rs:+2:72: +2:73
- goto -> bb23; // scope 0 at no-location
+ goto -> bb20; // scope 0 at no-location
}
- bb10: {
+ bb7: {
- _9 = (*_6); // scope 0 at $DIR/match-arm-scopes.rs:+2:70: +2:71
-- switchInt(move _9) -> [false: bb12, otherwise: bb11]; // scope 0 at $DIR/match-arm-scopes.rs:+2:42: +2:73
-+ switchInt(move _9) -> [false: bb9, otherwise: bb8]; // scope 0 at $DIR/match-arm-scopes.rs:+2:42: +2:73
+ _9 = (*_6); // scope 0 at $DIR/match_arm_scopes.rs:+2:70: +2:71
+- switchInt(move _9) -> [false: bb12, otherwise: bb11]; // scope 0 at $DIR/match_arm_scopes.rs:+2:42: +2:73
++ switchInt(move _9) -> [false: bb9, otherwise: bb8]; // scope 0 at $DIR/match_arm_scopes.rs:+2:42: +2:73
}
- bb11: {
+ bb8: {
- StorageDead(_10); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73
- StorageDead(_9); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73
-- FakeRead(ForMatchGuard, _3); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73
-- FakeRead(ForMatchGuard, _4); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73
-- FakeRead(ForGuardBinding, _6); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73
-- FakeRead(ForGuardBinding, _8); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73
- StorageLive(_5); // scope 0 at $DIR/match-arm-scopes.rs:+2:17: +2:18
- _5 = (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:+2:17: +2:18
- StorageLive(_7); // scope 0 at $DIR/match-arm-scopes.rs:+2:20: +2:21
- _7 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:+2:20: +2:21
-- goto -> bb7; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +4:6
-+ goto -> bb4; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +4:6
+ StorageDead(_10); // scope 0 at $DIR/match_arm_scopes.rs:+2:72: +2:73
+ StorageDead(_9); // scope 0 at $DIR/match_arm_scopes.rs:+2:72: +2:73
+- FakeRead(ForMatchGuard, _3); // scope 0 at $DIR/match_arm_scopes.rs:+2:72: +2:73
+- FakeRead(ForMatchGuard, _4); // scope 0 at $DIR/match_arm_scopes.rs:+2:72: +2:73
+- FakeRead(ForGuardBinding, _6); // scope 0 at $DIR/match_arm_scopes.rs:+2:72: +2:73
+- FakeRead(ForGuardBinding, _8); // scope 0 at $DIR/match_arm_scopes.rs:+2:72: +2:73
+ StorageLive(_5); // scope 0 at $DIR/match_arm_scopes.rs:+2:17: +2:18
+ _5 = (_2.1: bool); // scope 0 at $DIR/match_arm_scopes.rs:+2:17: +2:18
+ StorageLive(_7); // scope 0 at $DIR/match_arm_scopes.rs:+2:20: +2:21
+ _7 = move (_2.2: std::string::String); // scope 0 at $DIR/match_arm_scopes.rs:+2:20: +2:21
+- goto -> bb7; // scope 0 at $DIR/match_arm_scopes.rs:+1:5: +4:6
++ goto -> bb4; // scope 0 at $DIR/match_arm_scopes.rs:+1:5: +4:6
}
- bb12: {
+ bb9: {
- StorageDead(_10); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73
- StorageDead(_9); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73
- StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78
- StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78
-- falseEdge -> [real: bb2, imaginary: bb3]; // scope 0 at $DIR/match-arm-scopes.rs:+2:42: +2:73
-+ goto -> bb1; // scope 0 at $DIR/match-arm-scopes.rs:+2:42: +2:73
+ StorageDead(_10); // scope 0 at $DIR/match_arm_scopes.rs:+2:72: +2:73
+ StorageDead(_9); // scope 0 at $DIR/match_arm_scopes.rs:+2:72: +2:73
+ StorageDead(_8); // scope 0 at $DIR/match_arm_scopes.rs:+2:77: +2:78
+ StorageDead(_6); // scope 0 at $DIR/match_arm_scopes.rs:+2:77: +2:78
+- falseEdge -> [real: bb2, imaginary: bb3]; // scope 0 at $DIR/match_arm_scopes.rs:+2:42: +2:73
++ goto -> bb1; // scope 0 at $DIR/match_arm_scopes.rs:+2:42: +2:73
}
- bb13: {
+ bb10: {
- StorageLive(_6); // scope 0 at $DIR/match-arm-scopes.rs:+2:26: +2:27
- _6 = &(_2.0: bool); // scope 0 at $DIR/match-arm-scopes.rs:+2:26: +2:27
- StorageLive(_8); // scope 0 at $DIR/match-arm-scopes.rs:+2:36: +2:37
- _8 = &(_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:+2:36: +2:37
-- _3 = &shallow (_2.0: bool); // scope 0 at $DIR/match-arm-scopes.rs:+1:11: +1:16
-- _4 = &shallow (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:+1:11: +1:16
- StorageLive(_12); // scope 0 at $DIR/match-arm-scopes.rs:+2:42: +2:73
- StorageLive(_13); // scope 0 at $DIR/match-arm-scopes.rs:+2:45: +2:49
- _13 = _1; // scope 0 at $DIR/match-arm-scopes.rs:+2:45: +2:49
-- switchInt(move _13) -> [false: bb15, otherwise: bb14]; // scope 0 at $DIR/match-arm-scopes.rs:+2:45: +2:49
-+ switchInt(move _13) -> [false: bb12, otherwise: bb11]; // scope 0 at $DIR/match-arm-scopes.rs:+2:45: +2:49
+ StorageLive(_6); // scope 0 at $DIR/match_arm_scopes.rs:+2:26: +2:27
+ _6 = &(_2.0: bool); // scope 0 at $DIR/match_arm_scopes.rs:+2:26: +2:27
+ StorageLive(_8); // scope 0 at $DIR/match_arm_scopes.rs:+2:36: +2:37
+ _8 = &(_2.2: std::string::String); // scope 0 at $DIR/match_arm_scopes.rs:+2:36: +2:37
+- _3 = &shallow (_2.0: bool); // scope 0 at $DIR/match_arm_scopes.rs:+1:11: +1:16
+- _4 = &shallow (_2.1: bool); // scope 0 at $DIR/match_arm_scopes.rs:+1:11: +1:16
+ StorageLive(_12); // scope 0 at $DIR/match_arm_scopes.rs:+2:42: +2:73
+ StorageLive(_13); // scope 0 at $DIR/match_arm_scopes.rs:+2:45: +2:49
+ _13 = _1; // scope 0 at $DIR/match_arm_scopes.rs:+2:45: +2:49
+- switchInt(move _13) -> [false: bb15, otherwise: bb14]; // scope 0 at $DIR/match_arm_scopes.rs:+2:45: +2:49
++ switchInt(move _13) -> [false: bb12, otherwise: bb11]; // scope 0 at $DIR/match_arm_scopes.rs:+2:45: +2:49
}
- bb14: {
+ bb11: {
- _0 = const 3_i32; // scope 0 at $DIR/match-arm-scopes.rs:+2:59: +2:60
- StorageDead(_13); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73
- StorageDead(_12); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73
+ _0 = const 3_i32; // scope 0 at $DIR/match_arm_scopes.rs:+2:59: +2:60
+ StorageDead(_13); // scope 0 at $DIR/match_arm_scopes.rs:+2:72: +2:73
+ StorageDead(_12); // scope 0 at $DIR/match_arm_scopes.rs:+2:72: +2:73
- goto -> bb23; // scope 0 at no-location
+ goto -> bb20; // scope 0 at no-location
}
- bb15: {
+ bb12: {
- _12 = (*_6); // scope 0 at $DIR/match-arm-scopes.rs:+2:70: +2:71
-- switchInt(move _12) -> [false: bb17, otherwise: bb16]; // scope 0 at $DIR/match-arm-scopes.rs:+2:42: +2:73
-+ switchInt(move _12) -> [false: bb14, otherwise: bb13]; // scope 0 at $DIR/match-arm-scopes.rs:+2:42: +2:73
+ _12 = (*_6); // scope 0 at $DIR/match_arm_scopes.rs:+2:70: +2:71
+- switchInt(move _12) -> [false: bb17, otherwise: bb16]; // scope 0 at $DIR/match_arm_scopes.rs:+2:42: +2:73
++ switchInt(move _12) -> [false: bb14, otherwise: bb13]; // scope 0 at $DIR/match_arm_scopes.rs:+2:42: +2:73
}
- bb16: {
+ bb13: {
- StorageDead(_13); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73
- StorageDead(_12); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73
-- FakeRead(ForMatchGuard, _3); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73
-- FakeRead(ForMatchGuard, _4); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73
-- FakeRead(ForGuardBinding, _6); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73
-- FakeRead(ForGuardBinding, _8); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73
- StorageLive(_5); // scope 0 at $DIR/match-arm-scopes.rs:+2:26: +2:27
- _5 = (_2.0: bool); // scope 0 at $DIR/match-arm-scopes.rs:+2:26: +2:27
- StorageLive(_7); // scope 0 at $DIR/match-arm-scopes.rs:+2:36: +2:37
- _7 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:+2:36: +2:37
-- goto -> bb7; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +4:6
-+ goto -> bb4; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +4:6
+ StorageDead(_13); // scope 0 at $DIR/match_arm_scopes.rs:+2:72: +2:73
+ StorageDead(_12); // scope 0 at $DIR/match_arm_scopes.rs:+2:72: +2:73
+- FakeRead(ForMatchGuard, _3); // scope 0 at $DIR/match_arm_scopes.rs:+2:72: +2:73
+- FakeRead(ForMatchGuard, _4); // scope 0 at $DIR/match_arm_scopes.rs:+2:72: +2:73
+- FakeRead(ForGuardBinding, _6); // scope 0 at $DIR/match_arm_scopes.rs:+2:72: +2:73
+- FakeRead(ForGuardBinding, _8); // scope 0 at $DIR/match_arm_scopes.rs:+2:72: +2:73
+ StorageLive(_5); // scope 0 at $DIR/match_arm_scopes.rs:+2:26: +2:27
+ _5 = (_2.0: bool); // scope 0 at $DIR/match_arm_scopes.rs:+2:26: +2:27
+ StorageLive(_7); // scope 0 at $DIR/match_arm_scopes.rs:+2:36: +2:37
+ _7 = move (_2.2: std::string::String); // scope 0 at $DIR/match_arm_scopes.rs:+2:36: +2:37
+- goto -> bb7; // scope 0 at $DIR/match_arm_scopes.rs:+1:5: +4:6
++ goto -> bb4; // scope 0 at $DIR/match_arm_scopes.rs:+1:5: +4:6
}
- bb17: {
+ bb14: {
- StorageDead(_13); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73
- StorageDead(_12); // scope 0 at $DIR/match-arm-scopes.rs:+2:72: +2:73
- StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78
- StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78
-- falseEdge -> [real: bb4, imaginary: bb5]; // scope 0 at $DIR/match-arm-scopes.rs:+2:42: +2:73
-+ goto -> bb2; // scope 0 at $DIR/match-arm-scopes.rs:+2:42: +2:73
+ StorageDead(_13); // scope 0 at $DIR/match_arm_scopes.rs:+2:72: +2:73
+ StorageDead(_12); // scope 0 at $DIR/match_arm_scopes.rs:+2:72: +2:73
+ StorageDead(_8); // scope 0 at $DIR/match_arm_scopes.rs:+2:77: +2:78
+ StorageDead(_6); // scope 0 at $DIR/match_arm_scopes.rs:+2:77: +2:78
+- falseEdge -> [real: bb4, imaginary: bb5]; // scope 0 at $DIR/match_arm_scopes.rs:+2:42: +2:73
++ goto -> bb2; // scope 0 at $DIR/match_arm_scopes.rs:+2:42: +2:73
}
- bb18: {
+ bb15: {
- StorageDead(_7); // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78
- StorageDead(_5); // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78
- StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78
- StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78
-- goto -> bb22; // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78
-+ goto -> bb19; // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78
+ StorageDead(_7); // scope 0 at $DIR/match_arm_scopes.rs:+2:77: +2:78
+ StorageDead(_5); // scope 0 at $DIR/match_arm_scopes.rs:+2:77: +2:78
+ StorageDead(_8); // scope 0 at $DIR/match_arm_scopes.rs:+2:77: +2:78
+ StorageDead(_6); // scope 0 at $DIR/match_arm_scopes.rs:+2:77: +2:78
+- goto -> bb22; // scope 0 at $DIR/match_arm_scopes.rs:+2:77: +2:78
++ goto -> bb19; // scope 0 at $DIR/match_arm_scopes.rs:+2:77: +2:78
}
- bb19: {
+ bb16: {
- _0 = const 2_i32; // scope 2 at $DIR/match-arm-scopes.rs:+3:41: +3:42
-- drop(_16) -> [return: bb21, unwind: bb25]; // scope 0 at $DIR/match-arm-scopes.rs:+3:41: +3:42
-+ drop(_16) -> [return: bb18, unwind: bb22]; // scope 0 at $DIR/match-arm-scopes.rs:+3:41: +3:42
+ _0 = const 2_i32; // scope 2 at $DIR/match_arm_scopes.rs:+3:41: +3:42
+- drop(_16) -> [return: bb21, unwind: bb25]; // scope 0 at $DIR/match_arm_scopes.rs:+3:41: +3:42
++ drop(_16) -> [return: bb18, unwind: bb22]; // scope 0 at $DIR/match_arm_scopes.rs:+3:41: +3:42
}
- bb20: {
+ bb17: {
- StorageLive(_15); // scope 0 at $DIR/match-arm-scopes.rs:+3:16: +3:17
- _15 = (_2.1: bool); // scope 0 at $DIR/match-arm-scopes.rs:+3:16: +3:17
- StorageLive(_16); // scope 0 at $DIR/match-arm-scopes.rs:+3:19: +3:20
- _16 = move (_2.2: std::string::String); // scope 0 at $DIR/match-arm-scopes.rs:+3:19: +3:20
-- goto -> bb19; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +4:6
-+ goto -> bb16; // scope 0 at $DIR/match-arm-scopes.rs:+1:5: +4:6
+ StorageLive(_15); // scope 0 at $DIR/match_arm_scopes.rs:+3:16: +3:17
+ _15 = (_2.1: bool); // scope 0 at $DIR/match_arm_scopes.rs:+3:16: +3:17
+ StorageLive(_16); // scope 0 at $DIR/match_arm_scopes.rs:+3:19: +3:20
+ _16 = move (_2.2: std::string::String); // scope 0 at $DIR/match_arm_scopes.rs:+3:19: +3:20
+- goto -> bb19; // scope 0 at $DIR/match_arm_scopes.rs:+1:5: +4:6
++ goto -> bb16; // scope 0 at $DIR/match_arm_scopes.rs:+1:5: +4:6
}
- bb21: {
+ bb18: {
- StorageDead(_16); // scope 0 at $DIR/match-arm-scopes.rs:+3:41: +3:42
- StorageDead(_15); // scope 0 at $DIR/match-arm-scopes.rs:+3:41: +3:42
-- goto -> bb22; // scope 0 at $DIR/match-arm-scopes.rs:+3:41: +3:42
-+ goto -> bb19; // scope 0 at $DIR/match-arm-scopes.rs:+3:41: +3:42
+ StorageDead(_16); // scope 0 at $DIR/match_arm_scopes.rs:+3:41: +3:42
+ StorageDead(_15); // scope 0 at $DIR/match_arm_scopes.rs:+3:41: +3:42
+- goto -> bb22; // scope 0 at $DIR/match_arm_scopes.rs:+3:41: +3:42
++ goto -> bb19; // scope 0 at $DIR/match_arm_scopes.rs:+3:41: +3:42
}
- bb22: {
-- drop(_2) -> [return: bb24, unwind: bb26]; // scope 0 at $DIR/match-arm-scopes.rs:+5:1: +5:2
+- drop(_2) -> [return: bb24, unwind: bb26]; // scope 0 at $DIR/match_arm_scopes.rs:+5:1: +5:2
+ bb19: {
-+ goto -> bb26; // scope 0 at $DIR/match-arm-scopes.rs:+5:1: +5:2
++ goto -> bb26; // scope 0 at $DIR/match_arm_scopes.rs:+5:1: +5:2
}
- bb23: {
+ bb20: {
- StorageDead(_8); // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78
- StorageDead(_6); // scope 0 at $DIR/match-arm-scopes.rs:+2:77: +2:78
-- drop(_2) -> [return: bb24, unwind: bb26]; // scope 0 at $DIR/match-arm-scopes.rs:+5:1: +5:2
-+ drop(_2) -> [return: bb21, unwind: bb23]; // scope 0 at $DIR/match-arm-scopes.rs:+5:1: +5:2
+ StorageDead(_8); // scope 0 at $DIR/match_arm_scopes.rs:+2:77: +2:78
+ StorageDead(_6); // scope 0 at $DIR/match_arm_scopes.rs:+2:77: +2:78
+- drop(_2) -> [return: bb24, unwind: bb26]; // scope 0 at $DIR/match_arm_scopes.rs:+5:1: +5:2
++ drop(_2) -> [return: bb21, unwind: bb23]; // scope 0 at $DIR/match_arm_scopes.rs:+5:1: +5:2
}
- bb24: {
+ bb21: {
- return; // scope 0 at $DIR/match-arm-scopes.rs:+5:2: +5:2
+ return; // scope 0 at $DIR/match_arm_scopes.rs:+5:2: +5:2
}
- bb25 (cleanup): {
-- drop(_2) -> bb26; // scope 0 at $DIR/match-arm-scopes.rs:+5:1: +5:2
+- drop(_2) -> bb26; // scope 0 at $DIR/match_arm_scopes.rs:+5:1: +5:2
+ bb22 (cleanup): {
-+ goto -> bb27; // scope 0 at $DIR/match-arm-scopes.rs:+5:1: +5:2
++ goto -> bb27; // scope 0 at $DIR/match_arm_scopes.rs:+5:1: +5:2
}
- bb26 (cleanup): {
+ bb23 (cleanup): {
- resume; // scope 0 at $DIR/match-arm-scopes.rs:+0:1: +5:2
+ resume; // scope 0 at $DIR/match_arm_scopes.rs:+0:1: +5:2
+ }
+
+ bb24: {
-+ goto -> bb21; // scope 0 at $DIR/match-arm-scopes.rs:+5:1: +5:2
++ goto -> bb21; // scope 0 at $DIR/match_arm_scopes.rs:+5:1: +5:2
+ }
+
+ bb25 (cleanup): {
-+ goto -> bb23; // scope 0 at $DIR/match-arm-scopes.rs:+5:1: +5:2
++ goto -> bb23; // scope 0 at $DIR/match_arm_scopes.rs:+5:1: +5:2
+ }
+
+ bb26: {
-+ goto -> bb24; // scope 0 at $DIR/match-arm-scopes.rs:+5:1: +5:2
++ goto -> bb24; // scope 0 at $DIR/match_arm_scopes.rs:+5:1: +5:2
+ }
+
+ bb27 (cleanup): {
-+ goto -> bb23; // scope 0 at $DIR/match-arm-scopes.rs:+5:1: +5:2
++ goto -> bb23; // scope 0 at $DIR/match_arm_scopes.rs:+5:1: +5:2
}
}
--- /dev/null
+// ignore-wasm32-bare compiled with panic=abort by default
+// Test that StorageDead and Drops are generated properly for bindings in
+// matches:
+// * The MIR should only contain a single drop of `s` and `t`: at the end
+// of their respective arms.
+// * StorageDead and StorageLive statements are correctly matched up on
+// non-unwind paths.
+// * The visibility scopes of the match arms should be disjoint, and contain.
+// all of the bindings for that scope.
+// * No drop flags are used.
+
+// EMIT_MIR match_arm_scopes.complicated_match SimplifyCfg-initial.after ElaborateDrops.after
+fn complicated_match(cond: bool, items: (bool, bool, String)) -> i32 {
+ match items {
+ (false, a, s) | (a, false, s) if if cond { return 3 } else { a } => 1,
+ (true, b, t) | (false, b, t) => 2,
+ }
+}
+
+const CASES: &[(bool, bool, bool, i32)] = &[
+ (false, false, false, 2),
+ (false, false, true, 1),
+ (false, true, false, 1),
+ (false, true, true, 2),
+ (true, false, false, 3),
+ (true, false, true, 3),
+ (true, true, false, 3),
+ (true, true, true, 2),
+];
+
+fn main() {
+ for &(cond, items_1, items_2, result) in CASES {
+ assert_eq!(complicated_match(cond, (items_1, items_2, String::new())), result,);
+ }
+}
+++ /dev/null
-// MIR for `full_tested_match` after PromoteTemps
-
-fn full_tested_match() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/match_false_edges.rs:+0:28: +0:28
- let mut _1: (i32, i32); // in scope 0 at $DIR/match_false_edges.rs:+1:13: +5:6
- let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
- let mut _3: isize; // in scope 0 at $DIR/match_false_edges.rs:+2:9: +2:16
- let mut _4: &std::option::Option<i32>; // in scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
- let _5: i32; // in scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15
- let _6: &i32; // in scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15
- let mut _7: bool; // in scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27
- let mut _8: i32; // in scope 0 at $DIR/match_false_edges.rs:+2:35: +2:36
- let _9: i32; // in scope 0 at $DIR/match_false_edges.rs:+3:14: +3:15
- let mut _10: i32; // in scope 0 at $DIR/match_false_edges.rs:+3:24: +3:25
- let mut _11: &std::option::Option<i32>; // in scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15
- scope 1 {
- }
- scope 2 {
- debug x => _5; // in scope 2 at $DIR/match_false_edges.rs:+2:14: +2:15
- debug x => _6; // in scope 2 at $DIR/match_false_edges.rs:+2:14: +2:15
- }
- scope 3 {
- debug y => _9; // in scope 3 at $DIR/match_false_edges.rs:+3:14: +3:15
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:+1:13: +5:6
- StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
- _2 = Option::<i32>::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
- FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
- _3 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
- switchInt(move _3) -> [0_isize: bb1, 1_isize: bb2, otherwise: bb4]; // scope 0 at $DIR/match_false_edges.rs:+1:13: +1:27
- }
-
- bb1: {
- _1 = (const 3_i32, const 3_i32); // scope 0 at $DIR/match_false_edges.rs:+4:17: +4:23
- goto -> bb10; // scope 0 at $DIR/match_false_edges.rs:+4:17: +4:23
- }
-
- bb2: {
- falseEdge -> [real: bb5, imaginary: bb3]; // scope 0 at $DIR/match_false_edges.rs:+2:9: +2:16
- }
-
- bb3: {
- falseEdge -> [real: bb9, imaginary: bb1]; // scope 0 at $DIR/match_false_edges.rs:+3:9: +3:16
- }
-
- bb4: {
- unreachable; // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
- }
-
- bb5: {
- StorageLive(_6); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15
- _11 = const _; // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15
- // mir::Constant
- // + span: $DIR/match_false_edges.rs:14:14: 14:15
- // + literal: Const { ty: &Option<i32>, val: Unevaluated(full_tested_match, [], Some(promoted[0])) }
- _6 = &(((*_11) as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15
- _4 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
- StorageLive(_7); // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27
- _7 = guard() -> [return: bb6, unwind: bb11]; // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27
- // mir::Constant
- // + span: $DIR/match_false_edges.rs:14:20: 14:25
- // + literal: Const { ty: fn() -> bool {guard}, val: Value(<ZST>) }
- }
-
- bb6: {
- switchInt(move _7) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27
- }
-
- bb7: {
- StorageDead(_7); // scope 0 at $DIR/match_false_edges.rs:+2:26: +2:27
- FakeRead(ForMatchGuard, _4); // scope 0 at $DIR/match_false_edges.rs:+2:26: +2:27
- FakeRead(ForGuardBinding, _6); // scope 0 at $DIR/match_false_edges.rs:+2:26: +2:27
- StorageLive(_5); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15
- _5 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15
- StorageLive(_8); // scope 2 at $DIR/match_false_edges.rs:+2:35: +2:36
- _8 = _5; // scope 2 at $DIR/match_false_edges.rs:+2:35: +2:36
- _1 = (const 1_i32, move _8); // scope 2 at $DIR/match_false_edges.rs:+2:31: +2:37
- StorageDead(_8); // scope 2 at $DIR/match_false_edges.rs:+2:36: +2:37
- StorageDead(_5); // scope 0 at $DIR/match_false_edges.rs:+2:36: +2:37
- StorageDead(_6); // scope 0 at $DIR/match_false_edges.rs:+2:36: +2:37
- goto -> bb10; // scope 0 at $DIR/match_false_edges.rs:+2:36: +2:37
- }
-
- bb8: {
- StorageDead(_7); // scope 0 at $DIR/match_false_edges.rs:+2:26: +2:27
- StorageDead(_6); // scope 0 at $DIR/match_false_edges.rs:+2:36: +2:37
- goto -> bb3; // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27
- }
-
- bb9: {
- StorageLive(_9); // scope 0 at $DIR/match_false_edges.rs:+3:14: +3:15
- _9 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+3:14: +3:15
- StorageLive(_10); // scope 3 at $DIR/match_false_edges.rs:+3:24: +3:25
- _10 = _9; // scope 3 at $DIR/match_false_edges.rs:+3:24: +3:25
- _1 = (const 2_i32, move _10); // scope 3 at $DIR/match_false_edges.rs:+3:20: +3:26
- StorageDead(_10); // scope 3 at $DIR/match_false_edges.rs:+3:25: +3:26
- StorageDead(_9); // scope 0 at $DIR/match_false_edges.rs:+3:25: +3:26
- goto -> bb10; // scope 0 at $DIR/match_false_edges.rs:+3:25: +3:26
- }
-
- bb10: {
- StorageDead(_2); // scope 0 at $DIR/match_false_edges.rs:+5:6: +5:7
- StorageDead(_1); // scope 0 at $DIR/match_false_edges.rs:+5:6: +5:7
- _0 = const (); // scope 0 at $DIR/match_false_edges.rs:+0:28: +6:2
- return; // scope 0 at $DIR/match_false_edges.rs:+6:2: +6:2
- }
-
- bb11 (cleanup): {
- resume; // scope 0 at $DIR/match_false_edges.rs:+0:1: +6:2
- }
-}
+++ /dev/null
-// MIR for `full_tested_match2` before PromoteTemps
-
-fn full_tested_match2() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/match_false_edges.rs:+0:29: +0:29
- let mut _1: (i32, i32); // in scope 0 at $DIR/match_false_edges.rs:+1:13: +5:6
- let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
- let mut _3: isize; // in scope 0 at $DIR/match_false_edges.rs:+2:9: +2:16
- let mut _4: &std::option::Option<i32>; // in scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
- let _5: i32; // in scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15
- let _6: &i32; // in scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15
- let mut _7: bool; // in scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27
- let mut _8: i32; // in scope 0 at $DIR/match_false_edges.rs:+2:35: +2:36
- let _9: i32; // in scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15
- let mut _10: i32; // in scope 0 at $DIR/match_false_edges.rs:+4:24: +4:25
- scope 1 {
- }
- scope 2 {
- debug x => _5; // in scope 2 at $DIR/match_false_edges.rs:+2:14: +2:15
- debug x => _6; // in scope 2 at $DIR/match_false_edges.rs:+2:14: +2:15
- }
- scope 3 {
- debug y => _9; // in scope 3 at $DIR/match_false_edges.rs:+4:14: +4:15
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:+1:13: +5:6
- StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
- _2 = Option::<i32>::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
- FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
- _3 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
- switchInt(move _3) -> [0_isize: bb1, 1_isize: bb2, otherwise: bb4]; // scope 0 at $DIR/match_false_edges.rs:+1:13: +1:27
- }
-
- bb1: {
- falseEdge -> [real: bb9, imaginary: bb3]; // scope 0 at $DIR/match_false_edges.rs:+3:9: +3:13
- }
-
- bb2: {
- falseEdge -> [real: bb5, imaginary: bb1]; // scope 0 at $DIR/match_false_edges.rs:+2:9: +2:16
- }
-
- bb3: {
- StorageLive(_9); // scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15
- _9 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15
- StorageLive(_10); // scope 3 at $DIR/match_false_edges.rs:+4:24: +4:25
- _10 = _9; // scope 3 at $DIR/match_false_edges.rs:+4:24: +4:25
- _1 = (const 2_i32, move _10); // scope 3 at $DIR/match_false_edges.rs:+4:20: +4:26
- StorageDead(_10); // scope 3 at $DIR/match_false_edges.rs:+4:25: +4:26
- StorageDead(_9); // scope 0 at $DIR/match_false_edges.rs:+4:25: +4:26
- goto -> bb10; // scope 0 at $DIR/match_false_edges.rs:+4:25: +4:26
- }
-
- bb4: {
- unreachable; // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
- }
-
- bb5: {
- StorageLive(_6); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15
- _6 = &((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15
- _4 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:27
- StorageLive(_7); // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27
- _7 = guard() -> [return: bb6, unwind: bb11]; // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27
- // mir::Constant
- // + span: $DIR/match_false_edges.rs:25:20: 25:25
- // + literal: Const { ty: fn() -> bool {guard}, val: Value(<ZST>) }
- }
-
- bb6: {
- switchInt(move _7) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27
- }
-
- bb7: {
- StorageDead(_7); // scope 0 at $DIR/match_false_edges.rs:+2:26: +2:27
- FakeRead(ForMatchGuard, _4); // scope 0 at $DIR/match_false_edges.rs:+2:26: +2:27
- FakeRead(ForGuardBinding, _6); // scope 0 at $DIR/match_false_edges.rs:+2:26: +2:27
- StorageLive(_5); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15
- _5 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:15
- StorageLive(_8); // scope 2 at $DIR/match_false_edges.rs:+2:35: +2:36
- _8 = _5; // scope 2 at $DIR/match_false_edges.rs:+2:35: +2:36
- _1 = (const 1_i32, move _8); // scope 2 at $DIR/match_false_edges.rs:+2:31: +2:37
- StorageDead(_8); // scope 2 at $DIR/match_false_edges.rs:+2:36: +2:37
- StorageDead(_5); // scope 0 at $DIR/match_false_edges.rs:+2:36: +2:37
- StorageDead(_6); // scope 0 at $DIR/match_false_edges.rs:+2:36: +2:37
- goto -> bb10; // scope 0 at $DIR/match_false_edges.rs:+2:36: +2:37
- }
-
- bb8: {
- StorageDead(_7); // scope 0 at $DIR/match_false_edges.rs:+2:26: +2:27
- StorageDead(_6); // scope 0 at $DIR/match_false_edges.rs:+2:36: +2:37
- falseEdge -> [real: bb3, imaginary: bb1]; // scope 0 at $DIR/match_false_edges.rs:+2:20: +2:27
- }
-
- bb9: {
- _1 = (const 3_i32, const 3_i32); // scope 0 at $DIR/match_false_edges.rs:+3:17: +3:23
- goto -> bb10; // scope 0 at $DIR/match_false_edges.rs:+3:17: +3:23
- }
-
- bb10: {
- StorageDead(_2); // scope 0 at $DIR/match_false_edges.rs:+5:6: +5:7
- StorageDead(_1); // scope 0 at $DIR/match_false_edges.rs:+5:6: +5:7
- _0 = const (); // scope 0 at $DIR/match_false_edges.rs:+0:29: +6:2
- return; // scope 0 at $DIR/match_false_edges.rs:+6:2: +6:2
- }
-
- bb11 (cleanup): {
- resume; // scope 0 at $DIR/match_false_edges.rs:+0:1: +6:2
- }
-}
+++ /dev/null
-// MIR for `main` before PromoteTemps
-
-fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/match_false_edges.rs:+0:11: +0:11
- let mut _1: i32; // in scope 0 at $DIR/match_false_edges.rs:+1:13: +6:6
- let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26
- let mut _3: isize; // in scope 0 at $DIR/match_false_edges.rs:+4:9: +4:16
- let mut _4: isize; // in scope 0 at $DIR/match_false_edges.rs:+2:9: +2:17
- let mut _5: &std::option::Option<i32>; // in scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26
- let _6: i32; // in scope 0 at $DIR/match_false_edges.rs:+2:14: +2:16
- let _7: &i32; // in scope 0 at $DIR/match_false_edges.rs:+2:14: +2:16
- let mut _8: bool; // in scope 0 at $DIR/match_false_edges.rs:+2:21: +2:28
- let _9: std::option::Option<i32>; // in scope 0 at $DIR/match_false_edges.rs:+3:9: +3:11
- let _10: i32; // in scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15
- let _11: &i32; // in scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15
- let mut _12: bool; // in scope 0 at $DIR/match_false_edges.rs:+4:20: +4:29
- let mut _13: i32; // in scope 0 at $DIR/match_false_edges.rs:+4:27: +4:28
- let _14: std::option::Option<i32>; // in scope 0 at $DIR/match_false_edges.rs:+5:9: +5:11
- scope 1 {
- }
- scope 2 {
- debug _w => _6; // in scope 2 at $DIR/match_false_edges.rs:+2:14: +2:16
- debug _w => _7; // in scope 2 at $DIR/match_false_edges.rs:+2:14: +2:16
- }
- scope 3 {
- debug _x => _9; // in scope 3 at $DIR/match_false_edges.rs:+3:9: +3:11
- }
- scope 4 {
- debug y => _10; // in scope 4 at $DIR/match_false_edges.rs:+4:14: +4:15
- debug y => _11; // in scope 4 at $DIR/match_false_edges.rs:+4:14: +4:15
- }
- scope 5 {
- debug _z => _14; // in scope 5 at $DIR/match_false_edges.rs:+5:9: +5:11
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:+1:13: +6:6
- StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26
- _2 = Option::<i32>::Some(const 1_i32); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26
- FakeRead(ForMatchedPlace(None), _2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26
- _4 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26
- switchInt(move _4) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/match_false_edges.rs:+1:13: +1:26
- }
-
- bb1: {
- falseEdge -> [real: bb9, imaginary: bb4]; // scope 0 at $DIR/match_false_edges.rs:+3:9: +3:11
- }
-
- bb2: {
- falseEdge -> [real: bb5, imaginary: bb1]; // scope 0 at $DIR/match_false_edges.rs:+2:9: +2:17
- }
-
- bb3: {
- StorageLive(_14); // scope 0 at $DIR/match_false_edges.rs:+5:9: +5:11
- _14 = _2; // scope 0 at $DIR/match_false_edges.rs:+5:9: +5:11
- _1 = const 4_i32; // scope 5 at $DIR/match_false_edges.rs:+5:15: +5:16
- StorageDead(_14); // scope 0 at $DIR/match_false_edges.rs:+5:15: +5:16
- goto -> bb14; // scope 0 at $DIR/match_false_edges.rs:+5:15: +5:16
- }
-
- bb4: {
- falseEdge -> [real: bb10, imaginary: bb3]; // scope 0 at $DIR/match_false_edges.rs:+4:9: +4:16
- }
-
- bb5: {
- StorageLive(_7); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:16
- _7 = &((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:16
- _5 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26
- StorageLive(_8); // scope 0 at $DIR/match_false_edges.rs:+2:21: +2:28
- _8 = guard() -> [return: bb6, unwind: bb15]; // scope 0 at $DIR/match_false_edges.rs:+2:21: +2:28
- // mir::Constant
- // + span: $DIR/match_false_edges.rs:34:21: 34:26
- // + literal: Const { ty: fn() -> bool {guard}, val: Value(<ZST>) }
- }
-
- bb6: {
- switchInt(move _8) -> [false: bb8, otherwise: bb7]; // scope 0 at $DIR/match_false_edges.rs:+2:21: +2:28
- }
-
- bb7: {
- StorageDead(_8); // scope 0 at $DIR/match_false_edges.rs:+2:27: +2:28
- FakeRead(ForMatchGuard, _5); // scope 0 at $DIR/match_false_edges.rs:+2:27: +2:28
- FakeRead(ForGuardBinding, _7); // scope 0 at $DIR/match_false_edges.rs:+2:27: +2:28
- StorageLive(_6); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:16
- _6 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+2:14: +2:16
- _1 = const 1_i32; // scope 2 at $DIR/match_false_edges.rs:+2:32: +2:33
- StorageDead(_6); // scope 0 at $DIR/match_false_edges.rs:+2:32: +2:33
- StorageDead(_7); // scope 0 at $DIR/match_false_edges.rs:+2:32: +2:33
- goto -> bb14; // scope 0 at $DIR/match_false_edges.rs:+2:32: +2:33
- }
-
- bb8: {
- StorageDead(_8); // scope 0 at $DIR/match_false_edges.rs:+2:27: +2:28
- StorageDead(_7); // scope 0 at $DIR/match_false_edges.rs:+2:32: +2:33
- falseEdge -> [real: bb1, imaginary: bb1]; // scope 0 at $DIR/match_false_edges.rs:+2:21: +2:28
- }
-
- bb9: {
- StorageLive(_9); // scope 0 at $DIR/match_false_edges.rs:+3:9: +3:11
- _9 = _2; // scope 0 at $DIR/match_false_edges.rs:+3:9: +3:11
- _1 = const 2_i32; // scope 3 at $DIR/match_false_edges.rs:+3:15: +3:16
- StorageDead(_9); // scope 0 at $DIR/match_false_edges.rs:+3:15: +3:16
- goto -> bb14; // scope 0 at $DIR/match_false_edges.rs:+3:15: +3:16
- }
-
- bb10: {
- StorageLive(_11); // scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15
- _11 = &((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15
- _5 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:+1:19: +1:26
- StorageLive(_12); // scope 0 at $DIR/match_false_edges.rs:+4:20: +4:29
- StorageLive(_13); // scope 0 at $DIR/match_false_edges.rs:+4:27: +4:28
- _13 = (*_11); // scope 0 at $DIR/match_false_edges.rs:+4:27: +4:28
- _12 = guard2(move _13) -> [return: bb11, unwind: bb15]; // scope 0 at $DIR/match_false_edges.rs:+4:20: +4:29
- // mir::Constant
- // + span: $DIR/match_false_edges.rs:36:20: 36:26
- // + literal: Const { ty: fn(i32) -> bool {guard2}, val: Value(<ZST>) }
- }
-
- bb11: {
- switchInt(move _12) -> [false: bb13, otherwise: bb12]; // scope 0 at $DIR/match_false_edges.rs:+4:20: +4:29
- }
-
- bb12: {
- StorageDead(_13); // scope 0 at $DIR/match_false_edges.rs:+4:28: +4:29
- StorageDead(_12); // scope 0 at $DIR/match_false_edges.rs:+4:28: +4:29
- FakeRead(ForMatchGuard, _5); // scope 0 at $DIR/match_false_edges.rs:+4:28: +4:29
- FakeRead(ForGuardBinding, _11); // scope 0 at $DIR/match_false_edges.rs:+4:28: +4:29
- StorageLive(_10); // scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15
- _10 = ((_2 as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:+4:14: +4:15
- _1 = const 3_i32; // scope 4 at $DIR/match_false_edges.rs:+4:33: +4:34
- StorageDead(_10); // scope 0 at $DIR/match_false_edges.rs:+4:33: +4:34
- StorageDead(_11); // scope 0 at $DIR/match_false_edges.rs:+4:33: +4:34
- goto -> bb14; // scope 0 at $DIR/match_false_edges.rs:+4:33: +4:34
- }
-
- bb13: {
- StorageDead(_13); // scope 0 at $DIR/match_false_edges.rs:+4:28: +4:29
- StorageDead(_12); // scope 0 at $DIR/match_false_edges.rs:+4:28: +4:29
- StorageDead(_11); // scope 0 at $DIR/match_false_edges.rs:+4:33: +4:34
- falseEdge -> [real: bb3, imaginary: bb3]; // scope 0 at $DIR/match_false_edges.rs:+4:20: +4:29
- }
-
- bb14: {
- StorageDead(_2); // scope 0 at $DIR/match_false_edges.rs:+6:6: +6:7
- StorageDead(_1); // scope 0 at $DIR/match_false_edges.rs:+6:6: +6:7
- _0 = const (); // scope 0 at $DIR/match_false_edges.rs:+0:11: +7:2
- return; // scope 0 at $DIR/match_false_edges.rs:+7:2: +7:2
- }
-
- bb15 (cleanup): {
- resume; // scope 0 at $DIR/match_false_edges.rs:+0:1: +7:2
- }
-}
+++ /dev/null
-fn guard() -> bool {
- false
-}
-
-fn guard2(_: i32) -> bool {
- true
-}
-
-// no_mangle to make sure this gets instantiated even in an executable.
-#[no_mangle]
-// EMIT_MIR match_false_edges.full_tested_match.PromoteTemps.after.mir
-pub fn full_tested_match() {
- let _ = match Some(42) {
- Some(x) if guard() => (1, x),
- Some(y) => (2, y),
- None => (3, 3),
- };
-}
-
-// no_mangle to make sure this gets instantiated even in an executable.
-#[no_mangle]
-// EMIT_MIR match_false_edges.full_tested_match2.PromoteTemps.before.mir
-pub fn full_tested_match2() {
- let _ = match Some(42) {
- Some(x) if guard() => (1, x),
- None => (3, 3),
- Some(y) => (2, y),
- };
-}
-
-// EMIT_MIR match_false_edges.main.PromoteTemps.before.mir
-fn main() {
- let _ = match Some(1) {
- Some(_w) if guard() => 1,
- _x => 2,
- Some(y) if guard2(y) => 3,
- _z => 4,
- };
-}
+++ /dev/null
-// Basic test for named lifetime translation. Check that we
-// instantiate the types that appear in function arguments with
-// suitable variables and that we setup the outlives relationship
-// between R0 and R1 properly.
-
-// compile-flags: -Zverbose
-// ^^^^^^^^^ force compiler to dump more region information
-
-#![allow(warnings)]
-
-// EMIT_MIR named_lifetimes_basic.use_x.nll.0.mir
-fn use_x<'a, 'b: 'a, 'c>(w: &'a mut i32, x: &'b u32, y: &'a u32, z: &'c u32) -> bool { true }
-
-fn main() {
-}
--- /dev/null
+// Basic test for named lifetime translation. Check that we
+// instantiate the types that appear in function arguments with
+// suitable variables and that we setup the outlives relationship
+// between R0 and R1 properly.
+
+// compile-flags: -Zverbose
+// ^^^^^^^^^ force compiler to dump more region information
+
+#![allow(warnings)]
+
+// EMIT_MIR named_lifetimes_basic.use_x.nll.0.mir
+fn use_x<'a, 'b: 'a, 'c>(w: &'a mut i32, x: &'b u32, y: &'a u32, z: &'c u32) -> bool { true }
+
+fn main() {
+}
| '_#2r live at {bb0[0..=1]}
| '_#3r live at {bb0[0..=1]}
| '_#4r live at {bb0[0..=1]}
-| '_#1r: '_#5r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27) ($DIR/named-lifetimes-basic.rs:12:26: 12:27 (#0)
-| '_#1r: '_#7r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55) ($DIR/named-lifetimes-basic.rs:12:54: 12:55 (#0)
-| '_#2r: '_#6r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43) ($DIR/named-lifetimes-basic.rs:12:42: 12:43 (#0)
-| '_#3r: '_#8r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) ($DIR/named-lifetimes-basic.rs:12:66: 12:67 (#0)
-| '_#5r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:26: 12:27) ($DIR/named-lifetimes-basic.rs:12:26: 12:27 (#0)
-| '_#6r: '_#2r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:42: 12:43) ($DIR/named-lifetimes-basic.rs:12:42: 12:43 (#0)
-| '_#7r: '_#1r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:54: 12:55) ($DIR/named-lifetimes-basic.rs:12:54: 12:55 (#0)
-| '_#8r: '_#3r due to BoringNoLocation at All($DIR/named-lifetimes-basic.rs:12:66: 12:67) ($DIR/named-lifetimes-basic.rs:12:66: 12:67 (#0)
+| '_#1r: '_#5r due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:26: 12:27) ($DIR/named_lifetimes_basic.rs:12:26: 12:27 (#0)
+| '_#1r: '_#7r due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:54: 12:55) ($DIR/named_lifetimes_basic.rs:12:54: 12:55 (#0)
+| '_#2r: '_#6r due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:42: 12:43) ($DIR/named_lifetimes_basic.rs:12:42: 12:43 (#0)
+| '_#3r: '_#8r due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:66: 12:67) ($DIR/named_lifetimes_basic.rs:12:66: 12:67 (#0)
+| '_#5r: '_#1r due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:26: 12:27) ($DIR/named_lifetimes_basic.rs:12:26: 12:27 (#0)
+| '_#6r: '_#2r due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:42: 12:43) ($DIR/named_lifetimes_basic.rs:12:42: 12:43 (#0)
+| '_#7r: '_#1r due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:54: 12:55) ($DIR/named_lifetimes_basic.rs:12:54: 12:55 (#0)
+| '_#8r: '_#3r due to BoringNoLocation at All($DIR/named_lifetimes_basic.rs:12:66: 12:67) ($DIR/named_lifetimes_basic.rs:12:66: 12:67 (#0)
|
fn use_x(_1: &'_#5r mut i32, _2: &'_#6r u32, _3: &'_#7r u32, _4: &'_#8r u32) -> bool {
- debug w => _1; // in scope 0 at $DIR/named-lifetimes-basic.rs:+0:26: +0:27
- debug x => _2; // in scope 0 at $DIR/named-lifetimes-basic.rs:+0:42: +0:43
- debug y => _3; // in scope 0 at $DIR/named-lifetimes-basic.rs:+0:54: +0:55
- debug z => _4; // in scope 0 at $DIR/named-lifetimes-basic.rs:+0:66: +0:67
- let mut _0: bool; // return place in scope 0 at $DIR/named-lifetimes-basic.rs:+0:81: +0:85
+ debug w => _1; // in scope 0 at $DIR/named_lifetimes_basic.rs:+0:26: +0:27
+ debug x => _2; // in scope 0 at $DIR/named_lifetimes_basic.rs:+0:42: +0:43
+ debug y => _3; // in scope 0 at $DIR/named_lifetimes_basic.rs:+0:54: +0:55
+ debug z => _4; // in scope 0 at $DIR/named_lifetimes_basic.rs:+0:66: +0:67
+ let mut _0: bool; // return place in scope 0 at $DIR/named_lifetimes_basic.rs:+0:81: +0:85
bb0: {
- _0 = const ConstValue(Scalar(0x01): bool); // bb0[0]: scope 0 at $DIR/named-lifetimes-basic.rs:+0:88: +0:92
- return; // bb0[1]: scope 0 at $DIR/named-lifetimes-basic.rs:+0:94: +0:94
+ _0 = const ConstValue(Scalar(0x01): bool); // bb0[0]: scope 0 at $DIR/named_lifetimes_basic.rs:+0:88: +0:92
+ return; // bb0[1]: scope 0 at $DIR/named_lifetimes_basic.rs:+0:94: +0:94
}
}
+++ /dev/null
-// Basic test for liveness constraints: the region (`R1`) that appears
-// in the type of `p` includes the points after `&v[0]` up to (but not
-// including) the call to `use_x`. The `else` branch is not included.
-
-// compile-flags:-Zverbose
-// ^^^^^^^^^ force compiler to dump more region information
-
-#![allow(warnings)]
-
-fn use_x(_: usize) -> bool {
- true
-}
-
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
-// EMIT_MIR region_subtyping_basic.main.nll.0.mir
-fn main() {
- let mut v = [1, 2, 3];
- let p = &v[0];
- let q = p;
- if true {
- use_x(*q);
- } else {
- use_x(22);
- }
-}
| '_#2r live at {bb1[0]}
| '_#3r live at {bb1[1..=3]}
| '_#4r live at {bb1[4..=7], bb2[0..=2]}
-| '_#2r: '_#3r due to Assignment at Single(bb1[0]) ($DIR/region-subtyping-basic.rs:18:13: 18:18 (#0)
-| '_#3r: '_#4r due to Assignment at Single(bb1[3]) ($DIR/region-subtyping-basic.rs:19:13: 19:14 (#0)
+| '_#2r: '_#3r due to Assignment at Single(bb1[0]) ($DIR/region_subtyping_basic.rs:18:13: 18:18 (#0)
+| '_#3r: '_#4r due to Assignment at Single(bb1[3]) ($DIR/region_subtyping_basic.rs:19:13: 19:14 (#0)
|
fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/region-subtyping-basic.rs:+0:11: +0:11
- let mut _1: [usize; Const { ty: usize, kind: Value(Leaf(0x00000003)) }]; // in scope 0 at $DIR/region-subtyping-basic.rs:+1:9: +1:14
- let _3: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:+2:16: +2:17
- let mut _4: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:+2:14: +2:18
- let mut _5: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:+2:14: +2:18
- let mut _7: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:+4:8: +4:12
- let _8: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:+5:9: +5:18
- let mut _9: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:+5:15: +5:17
- let _10: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:+7:9: +7:18
+ let mut _0: (); // return place in scope 0 at $DIR/region_subtyping_basic.rs:+0:11: +0:11
+ let mut _1: [usize; Const { ty: usize, kind: Value(Leaf(0x00000003)) }]; // in scope 0 at $DIR/region_subtyping_basic.rs:+1:9: +1:14
+ let _3: usize; // in scope 0 at $DIR/region_subtyping_basic.rs:+2:16: +2:17
+ let mut _4: usize; // in scope 0 at $DIR/region_subtyping_basic.rs:+2:14: +2:18
+ let mut _5: bool; // in scope 0 at $DIR/region_subtyping_basic.rs:+2:14: +2:18
+ let mut _7: bool; // in scope 0 at $DIR/region_subtyping_basic.rs:+4:8: +4:12
+ let _8: bool; // in scope 0 at $DIR/region_subtyping_basic.rs:+5:9: +5:18
+ let mut _9: usize; // in scope 0 at $DIR/region_subtyping_basic.rs:+5:15: +5:17
+ let _10: bool; // in scope 0 at $DIR/region_subtyping_basic.rs:+7:9: +7:18
scope 1 {
- debug v => _1; // in scope 1 at $DIR/region-subtyping-basic.rs:+1:9: +1:14
- let _2: &'_#3r usize; // in scope 1 at $DIR/region-subtyping-basic.rs:+2:9: +2:10
+ debug v => _1; // in scope 1 at $DIR/region_subtyping_basic.rs:+1:9: +1:14
+ let _2: &'_#3r usize; // in scope 1 at $DIR/region_subtyping_basic.rs:+2:9: +2:10
scope 2 {
- debug p => _2; // in scope 2 at $DIR/region-subtyping-basic.rs:+2:9: +2:10
- let _6: &'_#4r usize; // in scope 2 at $DIR/region-subtyping-basic.rs:+3:9: +3:10
+ debug p => _2; // in scope 2 at $DIR/region_subtyping_basic.rs:+2:9: +2:10
+ let _6: &'_#4r usize; // in scope 2 at $DIR/region_subtyping_basic.rs:+3:9: +3:10
scope 3 {
- debug q => _6; // in scope 3 at $DIR/region-subtyping-basic.rs:+3:9: +3:10
+ debug q => _6; // in scope 3 at $DIR/region_subtyping_basic.rs:+3:9: +3:10
}
}
}
bb0: {
- StorageLive(_1); // bb0[0]: scope 0 at $DIR/region-subtyping-basic.rs:+1:9: +1:14
- _1 = [const ConstValue(Scalar(0x00000001): usize), const ConstValue(Scalar(0x00000002): usize), const ConstValue(Scalar(0x00000003): usize)]; // bb0[1]: scope 0 at $DIR/region-subtyping-basic.rs:+1:17: +1:26
- FakeRead(ForLet(None), _1); // bb0[2]: scope 0 at $DIR/region-subtyping-basic.rs:+1:9: +1:14
- StorageLive(_2); // bb0[3]: scope 1 at $DIR/region-subtyping-basic.rs:+2:9: +2:10
- StorageLive(_3); // bb0[4]: scope 1 at $DIR/region-subtyping-basic.rs:+2:16: +2:17
- _3 = const ConstValue(Scalar(0x00000000): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:+2:16: +2:17
- _4 = Len(_1); // bb0[6]: scope 1 at $DIR/region-subtyping-basic.rs:+2:14: +2:18
- _5 = Lt(_3, _4); // bb0[7]: scope 1 at $DIR/region-subtyping-basic.rs:+2:14: +2:18
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind: bb7]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:+2:14: +2:18
+ StorageLive(_1); // bb0[0]: scope 0 at $DIR/region_subtyping_basic.rs:+1:9: +1:14
+ _1 = [const ConstValue(Scalar(0x00000001): usize), const ConstValue(Scalar(0x00000002): usize), const ConstValue(Scalar(0x00000003): usize)]; // bb0[1]: scope 0 at $DIR/region_subtyping_basic.rs:+1:17: +1:26
+ FakeRead(ForLet(None), _1); // bb0[2]: scope 0 at $DIR/region_subtyping_basic.rs:+1:9: +1:14
+ StorageLive(_2); // bb0[3]: scope 1 at $DIR/region_subtyping_basic.rs:+2:9: +2:10
+ StorageLive(_3); // bb0[4]: scope 1 at $DIR/region_subtyping_basic.rs:+2:16: +2:17
+ _3 = const ConstValue(Scalar(0x00000000): usize); // bb0[5]: scope 1 at $DIR/region_subtyping_basic.rs:+2:16: +2:17
+ _4 = Len(_1); // bb0[6]: scope 1 at $DIR/region_subtyping_basic.rs:+2:14: +2:18
+ _5 = Lt(_3, _4); // bb0[7]: scope 1 at $DIR/region_subtyping_basic.rs:+2:14: +2:18
+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind: bb7]; // bb0[8]: scope 1 at $DIR/region_subtyping_basic.rs:+2:14: +2:18
}
bb1: {
- _2 = &'_#2r _1[_3]; // bb1[0]: scope 1 at $DIR/region-subtyping-basic.rs:+2:13: +2:18
- FakeRead(ForLet(None), _2); // bb1[1]: scope 1 at $DIR/region-subtyping-basic.rs:+2:9: +2:10
- StorageLive(_6); // bb1[2]: scope 2 at $DIR/region-subtyping-basic.rs:+3:9: +3:10
- _6 = _2; // bb1[3]: scope 2 at $DIR/region-subtyping-basic.rs:+3:13: +3:14
- FakeRead(ForLet(None), _6); // bb1[4]: scope 2 at $DIR/region-subtyping-basic.rs:+3:9: +3:10
- StorageLive(_7); // bb1[5]: scope 3 at $DIR/region-subtyping-basic.rs:+4:8: +4:12
- _7 = const ConstValue(Scalar(0x01): bool); // bb1[6]: scope 3 at $DIR/region-subtyping-basic.rs:+4:8: +4:12
- switchInt(move _7) -> [ConstValue(Scalar(0x00): bool): bb4, otherwise: bb2]; // bb1[7]: scope 3 at $DIR/region-subtyping-basic.rs:+4:8: +4:12
+ _2 = &'_#2r _1[_3]; // bb1[0]: scope 1 at $DIR/region_subtyping_basic.rs:+2:13: +2:18
+ FakeRead(ForLet(None), _2); // bb1[1]: scope 1 at $DIR/region_subtyping_basic.rs:+2:9: +2:10
+ StorageLive(_6); // bb1[2]: scope 2 at $DIR/region_subtyping_basic.rs:+3:9: +3:10
+ _6 = _2; // bb1[3]: scope 2 at $DIR/region_subtyping_basic.rs:+3:13: +3:14
+ FakeRead(ForLet(None), _6); // bb1[4]: scope 2 at $DIR/region_subtyping_basic.rs:+3:9: +3:10
+ StorageLive(_7); // bb1[5]: scope 3 at $DIR/region_subtyping_basic.rs:+4:8: +4:12
+ _7 = const ConstValue(Scalar(0x01): bool); // bb1[6]: scope 3 at $DIR/region_subtyping_basic.rs:+4:8: +4:12
+ switchInt(move _7) -> [ConstValue(Scalar(0x00): bool): bb4, otherwise: bb2]; // bb1[7]: scope 3 at $DIR/region_subtyping_basic.rs:+4:8: +4:12
}
bb2: {
- StorageLive(_8); // bb2[0]: scope 3 at $DIR/region-subtyping-basic.rs:+5:9: +5:18
- StorageLive(_9); // bb2[1]: scope 3 at $DIR/region-subtyping-basic.rs:+5:15: +5:17
- _9 = (*_6); // bb2[2]: scope 3 at $DIR/region-subtyping-basic.rs:+5:15: +5:17
- _8 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region-subtyping-basic.rs:+5:9: +5:18
+ StorageLive(_8); // bb2[0]: scope 3 at $DIR/region_subtyping_basic.rs:+5:9: +5:18
+ StorageLive(_9); // bb2[1]: scope 3 at $DIR/region_subtyping_basic.rs:+5:15: +5:17
+ _9 = (*_6); // bb2[2]: scope 3 at $DIR/region_subtyping_basic.rs:+5:15: +5:17
+ _8 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region_subtyping_basic.rs:+5:9: +5:18
// mir::Constant
- // + span: $DIR/region-subtyping-basic.rs:21:9: 21:14
+ // + span: $DIR/region_subtyping_basic.rs:21:9: 21:14
// + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(<ZST>) }
}
bb3: {
- StorageDead(_9); // bb3[0]: scope 3 at $DIR/region-subtyping-basic.rs:+5:17: +5:18
- StorageDead(_8); // bb3[1]: scope 3 at $DIR/region-subtyping-basic.rs:+5:18: +5:19
- _0 = const ConstValue(ZeroSized: ()); // bb3[2]: scope 3 at $DIR/region-subtyping-basic.rs:+4:13: +6:6
- goto -> bb6; // bb3[3]: scope 3 at $DIR/region-subtyping-basic.rs:+4:5: +8:6
+ StorageDead(_9); // bb3[0]: scope 3 at $DIR/region_subtyping_basic.rs:+5:17: +5:18
+ StorageDead(_8); // bb3[1]: scope 3 at $DIR/region_subtyping_basic.rs:+5:18: +5:19
+ _0 = const ConstValue(ZeroSized: ()); // bb3[2]: scope 3 at $DIR/region_subtyping_basic.rs:+4:13: +6:6
+ goto -> bb6; // bb3[3]: scope 3 at $DIR/region_subtyping_basic.rs:+4:5: +8:6
}
bb4: {
- StorageLive(_10); // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:+7:9: +7:18
- _10 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x00000016): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:+7:9: +7:18
+ StorageLive(_10); // bb4[0]: scope 3 at $DIR/region_subtyping_basic.rs:+7:9: +7:18
+ _10 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x00000016): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region_subtyping_basic.rs:+7:9: +7:18
// mir::Constant
- // + span: $DIR/region-subtyping-basic.rs:23:9: 23:14
+ // + span: $DIR/region_subtyping_basic.rs:23:9: 23:14
// + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(<ZST>) }
}
bb5: {
- StorageDead(_10); // bb5[0]: scope 3 at $DIR/region-subtyping-basic.rs:+7:18: +7:19
- _0 = const ConstValue(ZeroSized: ()); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:+6:12: +8:6
- goto -> bb6; // bb5[2]: scope 3 at $DIR/region-subtyping-basic.rs:+4:5: +8:6
+ StorageDead(_10); // bb5[0]: scope 3 at $DIR/region_subtyping_basic.rs:+7:18: +7:19
+ _0 = const ConstValue(ZeroSized: ()); // bb5[1]: scope 3 at $DIR/region_subtyping_basic.rs:+6:12: +8:6
+ goto -> bb6; // bb5[2]: scope 3 at $DIR/region_subtyping_basic.rs:+4:5: +8:6
}
bb6: {
- StorageDead(_7); // bb6[0]: scope 3 at $DIR/region-subtyping-basic.rs:+8:5: +8:6
- StorageDead(_6); // bb6[1]: scope 2 at $DIR/region-subtyping-basic.rs:+9:1: +9:2
- StorageDead(_3); // bb6[2]: scope 1 at $DIR/region-subtyping-basic.rs:+9:1: +9:2
- StorageDead(_2); // bb6[3]: scope 1 at $DIR/region-subtyping-basic.rs:+9:1: +9:2
- StorageDead(_1); // bb6[4]: scope 0 at $DIR/region-subtyping-basic.rs:+9:1: +9:2
- return; // bb6[5]: scope 0 at $DIR/region-subtyping-basic.rs:+9:2: +9:2
+ StorageDead(_7); // bb6[0]: scope 3 at $DIR/region_subtyping_basic.rs:+8:5: +8:6
+ StorageDead(_6); // bb6[1]: scope 2 at $DIR/region_subtyping_basic.rs:+9:1: +9:2
+ StorageDead(_3); // bb6[2]: scope 1 at $DIR/region_subtyping_basic.rs:+9:1: +9:2
+ StorageDead(_2); // bb6[3]: scope 1 at $DIR/region_subtyping_basic.rs:+9:1: +9:2
+ StorageDead(_1); // bb6[4]: scope 0 at $DIR/region_subtyping_basic.rs:+9:1: +9:2
+ return; // bb6[5]: scope 0 at $DIR/region_subtyping_basic.rs:+9:2: +9:2
}
bb7 (cleanup): {
- resume; // bb7[0]: scope 0 at $DIR/region-subtyping-basic.rs:+0:1: +9:2
+ resume; // bb7[0]: scope 0 at $DIR/region_subtyping_basic.rs:+0:1: +9:2
}
}
| '_#2r live at {bb1[0]}
| '_#3r live at {bb1[1..=3]}
| '_#4r live at {bb1[4..=7], bb2[0..=2]}
-| '_#2r: '_#3r due to Assignment at Single(bb1[0]) ($DIR/region-subtyping-basic.rs:18:13: 18:18 (#0)
-| '_#3r: '_#4r due to Assignment at Single(bb1[3]) ($DIR/region-subtyping-basic.rs:19:13: 19:14 (#0)
+| '_#2r: '_#3r due to Assignment at Single(bb1[0]) ($DIR/region_subtyping_basic.rs:18:13: 18:18 (#0)
+| '_#3r: '_#4r due to Assignment at Single(bb1[3]) ($DIR/region_subtyping_basic.rs:19:13: 19:14 (#0)
|
fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/region-subtyping-basic.rs:+0:11: +0:11
- let mut _1: [usize; Const { ty: usize, kind: Value(Leaf(0x0000000000000003)) }]; // in scope 0 at $DIR/region-subtyping-basic.rs:+1:9: +1:14
- let _3: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:+2:16: +2:17
- let mut _4: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:+2:14: +2:18
- let mut _5: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:+2:14: +2:18
- let mut _7: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:+4:8: +4:12
- let _8: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:+5:9: +5:18
- let mut _9: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:+5:15: +5:17
- let _10: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:+7:9: +7:18
+ let mut _0: (); // return place in scope 0 at $DIR/region_subtyping_basic.rs:+0:11: +0:11
+ let mut _1: [usize; Const { ty: usize, kind: Value(Leaf(0x0000000000000003)) }]; // in scope 0 at $DIR/region_subtyping_basic.rs:+1:9: +1:14
+ let _3: usize; // in scope 0 at $DIR/region_subtyping_basic.rs:+2:16: +2:17
+ let mut _4: usize; // in scope 0 at $DIR/region_subtyping_basic.rs:+2:14: +2:18
+ let mut _5: bool; // in scope 0 at $DIR/region_subtyping_basic.rs:+2:14: +2:18
+ let mut _7: bool; // in scope 0 at $DIR/region_subtyping_basic.rs:+4:8: +4:12
+ let _8: bool; // in scope 0 at $DIR/region_subtyping_basic.rs:+5:9: +5:18
+ let mut _9: usize; // in scope 0 at $DIR/region_subtyping_basic.rs:+5:15: +5:17
+ let _10: bool; // in scope 0 at $DIR/region_subtyping_basic.rs:+7:9: +7:18
scope 1 {
- debug v => _1; // in scope 1 at $DIR/region-subtyping-basic.rs:+1:9: +1:14
- let _2: &'_#3r usize; // in scope 1 at $DIR/region-subtyping-basic.rs:+2:9: +2:10
+ debug v => _1; // in scope 1 at $DIR/region_subtyping_basic.rs:+1:9: +1:14
+ let _2: &'_#3r usize; // in scope 1 at $DIR/region_subtyping_basic.rs:+2:9: +2:10
scope 2 {
- debug p => _2; // in scope 2 at $DIR/region-subtyping-basic.rs:+2:9: +2:10
- let _6: &'_#4r usize; // in scope 2 at $DIR/region-subtyping-basic.rs:+3:9: +3:10
+ debug p => _2; // in scope 2 at $DIR/region_subtyping_basic.rs:+2:9: +2:10
+ let _6: &'_#4r usize; // in scope 2 at $DIR/region_subtyping_basic.rs:+3:9: +3:10
scope 3 {
- debug q => _6; // in scope 3 at $DIR/region-subtyping-basic.rs:+3:9: +3:10
+ debug q => _6; // in scope 3 at $DIR/region_subtyping_basic.rs:+3:9: +3:10
}
}
}
bb0: {
- StorageLive(_1); // bb0[0]: scope 0 at $DIR/region-subtyping-basic.rs:+1:9: +1:14
- _1 = [const ConstValue(Scalar(0x0000000000000001): usize), const ConstValue(Scalar(0x0000000000000002): usize), const ConstValue(Scalar(0x0000000000000003): usize)]; // bb0[1]: scope 0 at $DIR/region-subtyping-basic.rs:+1:17: +1:26
- FakeRead(ForLet(None), _1); // bb0[2]: scope 0 at $DIR/region-subtyping-basic.rs:+1:9: +1:14
- StorageLive(_2); // bb0[3]: scope 1 at $DIR/region-subtyping-basic.rs:+2:9: +2:10
- StorageLive(_3); // bb0[4]: scope 1 at $DIR/region-subtyping-basic.rs:+2:16: +2:17
- _3 = const ConstValue(Scalar(0x0000000000000000): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:+2:16: +2:17
- _4 = Len(_1); // bb0[6]: scope 1 at $DIR/region-subtyping-basic.rs:+2:14: +2:18
- _5 = Lt(_3, _4); // bb0[7]: scope 1 at $DIR/region-subtyping-basic.rs:+2:14: +2:18
- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind: bb7]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:+2:14: +2:18
+ StorageLive(_1); // bb0[0]: scope 0 at $DIR/region_subtyping_basic.rs:+1:9: +1:14
+ _1 = [const ConstValue(Scalar(0x0000000000000001): usize), const ConstValue(Scalar(0x0000000000000002): usize), const ConstValue(Scalar(0x0000000000000003): usize)]; // bb0[1]: scope 0 at $DIR/region_subtyping_basic.rs:+1:17: +1:26
+ FakeRead(ForLet(None), _1); // bb0[2]: scope 0 at $DIR/region_subtyping_basic.rs:+1:9: +1:14
+ StorageLive(_2); // bb0[3]: scope 1 at $DIR/region_subtyping_basic.rs:+2:9: +2:10
+ StorageLive(_3); // bb0[4]: scope 1 at $DIR/region_subtyping_basic.rs:+2:16: +2:17
+ _3 = const ConstValue(Scalar(0x0000000000000000): usize); // bb0[5]: scope 1 at $DIR/region_subtyping_basic.rs:+2:16: +2:17
+ _4 = Len(_1); // bb0[6]: scope 1 at $DIR/region_subtyping_basic.rs:+2:14: +2:18
+ _5 = Lt(_3, _4); // bb0[7]: scope 1 at $DIR/region_subtyping_basic.rs:+2:14: +2:18
+ assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb1, unwind: bb7]; // bb0[8]: scope 1 at $DIR/region_subtyping_basic.rs:+2:14: +2:18
}
bb1: {
- _2 = &'_#2r _1[_3]; // bb1[0]: scope 1 at $DIR/region-subtyping-basic.rs:+2:13: +2:18
- FakeRead(ForLet(None), _2); // bb1[1]: scope 1 at $DIR/region-subtyping-basic.rs:+2:9: +2:10
- StorageLive(_6); // bb1[2]: scope 2 at $DIR/region-subtyping-basic.rs:+3:9: +3:10
- _6 = _2; // bb1[3]: scope 2 at $DIR/region-subtyping-basic.rs:+3:13: +3:14
- FakeRead(ForLet(None), _6); // bb1[4]: scope 2 at $DIR/region-subtyping-basic.rs:+3:9: +3:10
- StorageLive(_7); // bb1[5]: scope 3 at $DIR/region-subtyping-basic.rs:+4:8: +4:12
- _7 = const ConstValue(Scalar(0x01): bool); // bb1[6]: scope 3 at $DIR/region-subtyping-basic.rs:+4:8: +4:12
- switchInt(move _7) -> [ConstValue(Scalar(0x00): bool): bb4, otherwise: bb2]; // bb1[7]: scope 3 at $DIR/region-subtyping-basic.rs:+4:8: +4:12
+ _2 = &'_#2r _1[_3]; // bb1[0]: scope 1 at $DIR/region_subtyping_basic.rs:+2:13: +2:18
+ FakeRead(ForLet(None), _2); // bb1[1]: scope 1 at $DIR/region_subtyping_basic.rs:+2:9: +2:10
+ StorageLive(_6); // bb1[2]: scope 2 at $DIR/region_subtyping_basic.rs:+3:9: +3:10
+ _6 = _2; // bb1[3]: scope 2 at $DIR/region_subtyping_basic.rs:+3:13: +3:14
+ FakeRead(ForLet(None), _6); // bb1[4]: scope 2 at $DIR/region_subtyping_basic.rs:+3:9: +3:10
+ StorageLive(_7); // bb1[5]: scope 3 at $DIR/region_subtyping_basic.rs:+4:8: +4:12
+ _7 = const ConstValue(Scalar(0x01): bool); // bb1[6]: scope 3 at $DIR/region_subtyping_basic.rs:+4:8: +4:12
+ switchInt(move _7) -> [ConstValue(Scalar(0x00): bool): bb4, otherwise: bb2]; // bb1[7]: scope 3 at $DIR/region_subtyping_basic.rs:+4:8: +4:12
}
bb2: {
- StorageLive(_8); // bb2[0]: scope 3 at $DIR/region-subtyping-basic.rs:+5:9: +5:18
- StorageLive(_9); // bb2[1]: scope 3 at $DIR/region-subtyping-basic.rs:+5:15: +5:17
- _9 = (*_6); // bb2[2]: scope 3 at $DIR/region-subtyping-basic.rs:+5:15: +5:17
- _8 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region-subtyping-basic.rs:+5:9: +5:18
+ StorageLive(_8); // bb2[0]: scope 3 at $DIR/region_subtyping_basic.rs:+5:9: +5:18
+ StorageLive(_9); // bb2[1]: scope 3 at $DIR/region_subtyping_basic.rs:+5:15: +5:17
+ _9 = (*_6); // bb2[2]: scope 3 at $DIR/region_subtyping_basic.rs:+5:15: +5:17
+ _8 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(move _9) -> [return: bb3, unwind: bb7]; // bb2[3]: scope 3 at $DIR/region_subtyping_basic.rs:+5:9: +5:18
// mir::Constant
- // + span: $DIR/region-subtyping-basic.rs:21:9: 21:14
+ // + span: $DIR/region_subtyping_basic.rs:21:9: 21:14
// + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(<ZST>) }
}
bb3: {
- StorageDead(_9); // bb3[0]: scope 3 at $DIR/region-subtyping-basic.rs:+5:17: +5:18
- StorageDead(_8); // bb3[1]: scope 3 at $DIR/region-subtyping-basic.rs:+5:18: +5:19
- _0 = const ConstValue(ZeroSized: ()); // bb3[2]: scope 3 at $DIR/region-subtyping-basic.rs:+4:13: +6:6
- goto -> bb6; // bb3[3]: scope 3 at $DIR/region-subtyping-basic.rs:+4:5: +8:6
+ StorageDead(_9); // bb3[0]: scope 3 at $DIR/region_subtyping_basic.rs:+5:17: +5:18
+ StorageDead(_8); // bb3[1]: scope 3 at $DIR/region_subtyping_basic.rs:+5:18: +5:19
+ _0 = const ConstValue(ZeroSized: ()); // bb3[2]: scope 3 at $DIR/region_subtyping_basic.rs:+4:13: +6:6
+ goto -> bb6; // bb3[3]: scope 3 at $DIR/region_subtyping_basic.rs:+4:5: +8:6
}
bb4: {
- StorageLive(_10); // bb4[0]: scope 3 at $DIR/region-subtyping-basic.rs:+7:9: +7:18
- _10 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x0000000000000016): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region-subtyping-basic.rs:+7:9: +7:18
+ StorageLive(_10); // bb4[0]: scope 3 at $DIR/region_subtyping_basic.rs:+7:9: +7:18
+ _10 = ConstValue(ZeroSized: fn(usize) -> bool {use_x})(const ConstValue(Scalar(0x0000000000000016): usize)) -> [return: bb5, unwind: bb7]; // bb4[1]: scope 3 at $DIR/region_subtyping_basic.rs:+7:9: +7:18
// mir::Constant
- // + span: $DIR/region-subtyping-basic.rs:23:9: 23:14
+ // + span: $DIR/region_subtyping_basic.rs:23:9: 23:14
// + literal: Const { ty: fn(usize) -> bool {use_x}, val: Value(<ZST>) }
}
bb5: {
- StorageDead(_10); // bb5[0]: scope 3 at $DIR/region-subtyping-basic.rs:+7:18: +7:19
- _0 = const ConstValue(ZeroSized: ()); // bb5[1]: scope 3 at $DIR/region-subtyping-basic.rs:+6:12: +8:6
- goto -> bb6; // bb5[2]: scope 3 at $DIR/region-subtyping-basic.rs:+4:5: +8:6
+ StorageDead(_10); // bb5[0]: scope 3 at $DIR/region_subtyping_basic.rs:+7:18: +7:19
+ _0 = const ConstValue(ZeroSized: ()); // bb5[1]: scope 3 at $DIR/region_subtyping_basic.rs:+6:12: +8:6
+ goto -> bb6; // bb5[2]: scope 3 at $DIR/region_subtyping_basic.rs:+4:5: +8:6
}
bb6: {
- StorageDead(_7); // bb6[0]: scope 3 at $DIR/region-subtyping-basic.rs:+8:5: +8:6
- StorageDead(_6); // bb6[1]: scope 2 at $DIR/region-subtyping-basic.rs:+9:1: +9:2
- StorageDead(_3); // bb6[2]: scope 1 at $DIR/region-subtyping-basic.rs:+9:1: +9:2
- StorageDead(_2); // bb6[3]: scope 1 at $DIR/region-subtyping-basic.rs:+9:1: +9:2
- StorageDead(_1); // bb6[4]: scope 0 at $DIR/region-subtyping-basic.rs:+9:1: +9:2
- return; // bb6[5]: scope 0 at $DIR/region-subtyping-basic.rs:+9:2: +9:2
+ StorageDead(_7); // bb6[0]: scope 3 at $DIR/region_subtyping_basic.rs:+8:5: +8:6
+ StorageDead(_6); // bb6[1]: scope 2 at $DIR/region_subtyping_basic.rs:+9:1: +9:2
+ StorageDead(_3); // bb6[2]: scope 1 at $DIR/region_subtyping_basic.rs:+9:1: +9:2
+ StorageDead(_2); // bb6[3]: scope 1 at $DIR/region_subtyping_basic.rs:+9:1: +9:2
+ StorageDead(_1); // bb6[4]: scope 0 at $DIR/region_subtyping_basic.rs:+9:1: +9:2
+ return; // bb6[5]: scope 0 at $DIR/region_subtyping_basic.rs:+9:2: +9:2
}
bb7 (cleanup): {
- resume; // bb7[0]: scope 0 at $DIR/region-subtyping-basic.rs:+0:1: +9:2
+ resume; // bb7[0]: scope 0 at $DIR/region_subtyping_basic.rs:+0:1: +9:2
}
}
--- /dev/null
+// Basic test for liveness constraints: the region (`R1`) that appears
+// in the type of `p` includes the points after `&v[0]` up to (but not
+// including) the call to `use_x`. The `else` branch is not included.
+
+// compile-flags:-Zverbose
+// ^^^^^^^^^ force compiler to dump more region information
+
+#![allow(warnings)]
+
+fn use_x(_: usize) -> bool {
+ true
+}
+
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
+// EMIT_MIR region_subtyping_basic.main.nll.0.mir
+fn main() {
+ let mut v = [1, 2, 3];
+ let p = &v[0];
+ let q = p;
+ if true {
+ use_x(*q);
+ } else {
+ use_x(22);
+ }
+}
+++ /dev/null
-// ignore-wasm32-bare compiled with panic=abort by default
-
-// Ensure that there are no drop terminators in `unwrap<T>` (except the one along the cleanup
-// path).
-
-// EMIT_MIR no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir
-fn unwrap<T>(opt: Option<T>) -> T {
- match opt {
- Some(x) => x,
- None => panic!(),
- }
-}
-
-fn main() {
- let _ = unwrap(Some(1i32));
-}
+++ /dev/null
-// ignore-wasm32-bare compiled with panic=abort by default
-
-// Test that after the call to `std::mem::drop` we do not generate a
-// MIR drop of the argument. (We used to have a `DROP(_2)` in the code
-// below, as part of bb3.)
-
-// EMIT_MIR no_spurious_drop_after_call.main.ElaborateDrops.before.mir
-fn main() {
- std::mem::drop("".to_string());
-}
--- /dev/null
+// ignore-wasm32-bare compiled with panic=abort by default
+
+// Ensure that there are no drop terminators in `unwrap<T>` (except the one along the cleanup
+// path).
+
+// EMIT_MIR no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir
+fn unwrap<T>(opt: Option<T>) -> T {
+ match opt {
+ Some(x) => x,
+ None => panic!(),
+ }
+}
+
+fn main() {
+ let _ = unwrap(Some(1i32));
+}
// MIR for `unwrap` after SimplifyCfg-elaborate-drops
fn unwrap(_1: Option<T>) -> T {
- debug opt => _1; // in scope 0 at $DIR/no-drop-for-inactive-variant.rs:+0:14: +0:17
- let mut _0: T; // return place in scope 0 at $DIR/no-drop-for-inactive-variant.rs:+0:33: +0:34
- let mut _2: isize; // in scope 0 at $DIR/no-drop-for-inactive-variant.rs:+2:9: +2:16
- let _3: T; // in scope 0 at $DIR/no-drop-for-inactive-variant.rs:+2:14: +2:15
+ debug opt => _1; // in scope 0 at $DIR/no_drop_for_inactive_variant.rs:+0:14: +0:17
+ let mut _0: T; // return place in scope 0 at $DIR/no_drop_for_inactive_variant.rs:+0:33: +0:34
+ let mut _2: isize; // in scope 0 at $DIR/no_drop_for_inactive_variant.rs:+2:9: +2:16
+ let _3: T; // in scope 0 at $DIR/no_drop_for_inactive_variant.rs:+2:14: +2:15
let mut _4: !; // in scope 0 at $SRC_DIR/std/src/panic.rs:LL:COL
- let mut _5: isize; // in scope 0 at $DIR/no-drop-for-inactive-variant.rs:+5:1: +5:2
- let mut _6: isize; // in scope 0 at $DIR/no-drop-for-inactive-variant.rs:+5:1: +5:2
- let mut _7: isize; // in scope 0 at $DIR/no-drop-for-inactive-variant.rs:+5:1: +5:2
+ let mut _5: isize; // in scope 0 at $DIR/no_drop_for_inactive_variant.rs:+5:1: +5:2
+ let mut _6: isize; // in scope 0 at $DIR/no_drop_for_inactive_variant.rs:+5:1: +5:2
+ let mut _7: isize; // in scope 0 at $DIR/no_drop_for_inactive_variant.rs:+5:1: +5:2
scope 1 {
- debug x => _3; // in scope 1 at $DIR/no-drop-for-inactive-variant.rs:+2:14: +2:15
+ debug x => _3; // in scope 1 at $DIR/no_drop_for_inactive_variant.rs:+2:14: +2:15
}
bb0: {
- _2 = discriminant(_1); // scope 0 at $DIR/no-drop-for-inactive-variant.rs:+1:11: +1:14
- switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/no-drop-for-inactive-variant.rs:+1:5: +1:14
+ _2 = discriminant(_1); // scope 0 at $DIR/no_drop_for_inactive_variant.rs:+1:11: +1:14
+ switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/no_drop_for_inactive_variant.rs:+1:5: +1:14
}
bb1: {
}
bb2: {
- unreachable; // scope 0 at $DIR/no-drop-for-inactive-variant.rs:+1:11: +1:14
+ unreachable; // scope 0 at $DIR/no_drop_for_inactive_variant.rs:+1:11: +1:14
}
bb3: {
- StorageLive(_3); // scope 0 at $DIR/no-drop-for-inactive-variant.rs:+2:14: +2:15
- _3 = move ((_1 as Some).0: T); // scope 0 at $DIR/no-drop-for-inactive-variant.rs:+2:14: +2:15
- _0 = move _3; // scope 1 at $DIR/no-drop-for-inactive-variant.rs:+2:20: +2:21
- StorageDead(_3); // scope 0 at $DIR/no-drop-for-inactive-variant.rs:+2:20: +2:21
- _5 = discriminant(_1); // scope 0 at $DIR/no-drop-for-inactive-variant.rs:+5:1: +5:2
- return; // scope 0 at $DIR/no-drop-for-inactive-variant.rs:+5:2: +5:2
+ StorageLive(_3); // scope 0 at $DIR/no_drop_for_inactive_variant.rs:+2:14: +2:15
+ _3 = move ((_1 as Some).0: T); // scope 0 at $DIR/no_drop_for_inactive_variant.rs:+2:14: +2:15
+ _0 = move _3; // scope 1 at $DIR/no_drop_for_inactive_variant.rs:+2:20: +2:21
+ StorageDead(_3); // scope 0 at $DIR/no_drop_for_inactive_variant.rs:+2:20: +2:21
+ _5 = discriminant(_1); // scope 0 at $DIR/no_drop_for_inactive_variant.rs:+5:1: +5:2
+ return; // scope 0 at $DIR/no_drop_for_inactive_variant.rs:+5:2: +5:2
}
bb4 (cleanup): {
- _7 = discriminant(_1); // scope 0 at $DIR/no-drop-for-inactive-variant.rs:+5:1: +5:2
- resume; // scope 0 at $DIR/no-drop-for-inactive-variant.rs:+0:1: +5:2
+ _7 = discriminant(_1); // scope 0 at $DIR/no_drop_for_inactive_variant.rs:+5:1: +5:2
+ resume; // scope 0 at $DIR/no_drop_for_inactive_variant.rs:+0:1: +5:2
}
}
// MIR for `main` before ElaborateDrops
fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/no-spurious-drop-after-call.rs:+0:11: +0:11
- let _1: (); // in scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:5: +1:35
- let mut _2: std::string::String; // in scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:20: +1:34
- let mut _3: &str; // in scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:20: +1:34
- let _4: &str; // in scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:20: +1:22
+ let mut _0: (); // return place in scope 0 at $DIR/no_spurious_drop_after_call.rs:+0:11: +0:11
+ let _1: (); // in scope 0 at $DIR/no_spurious_drop_after_call.rs:+1:5: +1:35
+ let mut _2: std::string::String; // in scope 0 at $DIR/no_spurious_drop_after_call.rs:+1:20: +1:34
+ let mut _3: &str; // in scope 0 at $DIR/no_spurious_drop_after_call.rs:+1:20: +1:34
+ let _4: &str; // in scope 0 at $DIR/no_spurious_drop_after_call.rs:+1:20: +1:22
bb0: {
- StorageLive(_1); // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:5: +1:35
- StorageLive(_2); // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:20: +1:34
- StorageLive(_3); // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:20: +1:34
- StorageLive(_4); // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:20: +1:22
- _4 = const ""; // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:20: +1:22
+ StorageLive(_1); // scope 0 at $DIR/no_spurious_drop_after_call.rs:+1:5: +1:35
+ StorageLive(_2); // scope 0 at $DIR/no_spurious_drop_after_call.rs:+1:20: +1:34
+ StorageLive(_3); // scope 0 at $DIR/no_spurious_drop_after_call.rs:+1:20: +1:34
+ StorageLive(_4); // scope 0 at $DIR/no_spurious_drop_after_call.rs:+1:20: +1:22
+ _4 = const ""; // scope 0 at $DIR/no_spurious_drop_after_call.rs:+1:20: +1:22
// mir::Constant
- // + span: $DIR/no-spurious-drop-after-call.rs:9:20: 9:22
+ // + span: $DIR/no_spurious_drop_after_call.rs:9:20: 9:22
// + literal: Const { ty: &str, val: Value(Slice(..)) }
- _3 = &(*_4); // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:20: +1:34
- _2 = <str as ToString>::to_string(move _3) -> bb1; // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:20: +1:34
+ _3 = &(*_4); // scope 0 at $DIR/no_spurious_drop_after_call.rs:+1:20: +1:34
+ _2 = <str as ToString>::to_string(move _3) -> bb1; // scope 0 at $DIR/no_spurious_drop_after_call.rs:+1:20: +1:34
// mir::Constant
- // + span: $DIR/no-spurious-drop-after-call.rs:9:23: 9:32
+ // + span: $DIR/no_spurious_drop_after_call.rs:9:23: 9:32
// + literal: Const { ty: for<'a> fn(&'a str) -> String {<str as ToString>::to_string}, val: Value(<ZST>) }
}
bb1: {
- StorageDead(_3); // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:33: +1:34
- _1 = std::mem::drop::<String>(move _2) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:5: +1:35
+ StorageDead(_3); // scope 0 at $DIR/no_spurious_drop_after_call.rs:+1:33: +1:34
+ _1 = std::mem::drop::<String>(move _2) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/no_spurious_drop_after_call.rs:+1:5: +1:35
// mir::Constant
- // + span: $DIR/no-spurious-drop-after-call.rs:9:5: 9:19
+ // + span: $DIR/no_spurious_drop_after_call.rs:9:5: 9:19
// + literal: Const { ty: fn(String) {std::mem::drop::<String>}, val: Value(<ZST>) }
}
bb2: {
- StorageDead(_2); // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:34: +1:35
- StorageDead(_4); // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:35: +1:36
- StorageDead(_1); // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:35: +1:36
- _0 = const (); // scope 0 at $DIR/no-spurious-drop-after-call.rs:+0:11: +2:2
- return; // scope 0 at $DIR/no-spurious-drop-after-call.rs:+2:2: +2:2
+ StorageDead(_2); // scope 0 at $DIR/no_spurious_drop_after_call.rs:+1:34: +1:35
+ StorageDead(_4); // scope 0 at $DIR/no_spurious_drop_after_call.rs:+1:35: +1:36
+ StorageDead(_1); // scope 0 at $DIR/no_spurious_drop_after_call.rs:+1:35: +1:36
+ _0 = const (); // scope 0 at $DIR/no_spurious_drop_after_call.rs:+0:11: +2:2
+ return; // scope 0 at $DIR/no_spurious_drop_after_call.rs:+2:2: +2:2
}
bb3 (cleanup): {
- drop(_2) -> bb4; // scope 0 at $DIR/no-spurious-drop-after-call.rs:+1:34: +1:35
+ drop(_2) -> bb4; // scope 0 at $DIR/no_spurious_drop_after_call.rs:+1:34: +1:35
}
bb4 (cleanup): {
- resume; // scope 0 at $DIR/no-spurious-drop-after-call.rs:+0:1: +2:2
+ resume; // scope 0 at $DIR/no_spurious_drop_after_call.rs:+0:1: +2:2
}
}
--- /dev/null
+// ignore-wasm32-bare compiled with panic=abort by default
+
+// Test that after the call to `std::mem::drop` we do not generate a
+// MIR drop of the argument. (We used to have a `DROP(_2)` in the code
+// below, as part of bb3.)
+
+// EMIT_MIR no_spurious_drop_after_call.main.ElaborateDrops.before.mir
+fn main() {
+ std::mem::drop("".to_string());
+}
+++ /dev/null
-// unit-test: RenameReturnPlace
-
-// EMIT_MIR nrvo_simple.nrvo.RenameReturnPlace.diff
-fn nrvo(init: fn(&mut [u8; 1024])) -> [u8; 1024] {
- let mut buf = [0; 1024];
- init(&mut buf);
- buf
-}
-
-fn main() {
- let _ = nrvo(|buf| { buf[4] = 4; });
-}
+ // MIR for `nrvo` after RenameReturnPlace
fn nrvo(_1: for<'a> fn(&'a mut [u8; 1024])) -> [u8; 1024] {
- debug init => _1; // in scope 0 at $DIR/nrvo-simple.rs:+0:9: +0:13
-- let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/nrvo-simple.rs:+0:39: +0:49
-+ let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/nrvo-simple.rs:+1:9: +1:16
- let mut _2: [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:+1:9: +1:16
- let _3: (); // in scope 0 at $DIR/nrvo-simple.rs:+2:5: +2:19
- let mut _4: for<'a> fn(&'a mut [u8; 1024]); // in scope 0 at $DIR/nrvo-simple.rs:+2:5: +2:9
- let mut _5: &mut [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:+2:10: +2:18
- let mut _6: &mut [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:+2:10: +2:18
+ debug init => _1; // in scope 0 at $DIR/nrvo_simple.rs:+0:9: +0:13
+- let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/nrvo_simple.rs:+0:39: +0:49
++ let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/nrvo_simple.rs:+1:9: +1:16
+ let mut _2: [u8; 1024]; // in scope 0 at $DIR/nrvo_simple.rs:+1:9: +1:16
+ let _3: (); // in scope 0 at $DIR/nrvo_simple.rs:+2:5: +2:19
+ let mut _4: for<'a> fn(&'a mut [u8; 1024]); // in scope 0 at $DIR/nrvo_simple.rs:+2:5: +2:9
+ let mut _5: &mut [u8; 1024]; // in scope 0 at $DIR/nrvo_simple.rs:+2:10: +2:18
+ let mut _6: &mut [u8; 1024]; // in scope 0 at $DIR/nrvo_simple.rs:+2:10: +2:18
scope 1 {
-- debug buf => _2; // in scope 1 at $DIR/nrvo-simple.rs:+1:9: +1:16
-+ debug buf => _0; // in scope 1 at $DIR/nrvo-simple.rs:+1:9: +1:16
+- debug buf => _2; // in scope 1 at $DIR/nrvo_simple.rs:+1:9: +1:16
++ debug buf => _0; // in scope 1 at $DIR/nrvo_simple.rs:+1:9: +1:16
}
bb0: {
-- StorageLive(_2); // scope 0 at $DIR/nrvo-simple.rs:+1:9: +1:16
-- _2 = [const 0_u8; 1024]; // scope 0 at $DIR/nrvo-simple.rs:+1:19: +1:28
-+ _0 = [const 0_u8; 1024]; // scope 0 at $DIR/nrvo-simple.rs:+1:19: +1:28
- StorageLive(_3); // scope 1 at $DIR/nrvo-simple.rs:+2:5: +2:19
- StorageLive(_4); // scope 1 at $DIR/nrvo-simple.rs:+2:5: +2:9
- _4 = _1; // scope 1 at $DIR/nrvo-simple.rs:+2:5: +2:9
- StorageLive(_5); // scope 1 at $DIR/nrvo-simple.rs:+2:10: +2:18
- StorageLive(_6); // scope 1 at $DIR/nrvo-simple.rs:+2:10: +2:18
-- _6 = &mut _2; // scope 1 at $DIR/nrvo-simple.rs:+2:10: +2:18
-+ _6 = &mut _0; // scope 1 at $DIR/nrvo-simple.rs:+2:10: +2:18
- _5 = &mut (*_6); // scope 1 at $DIR/nrvo-simple.rs:+2:10: +2:18
- _3 = move _4(move _5) -> bb1; // scope 1 at $DIR/nrvo-simple.rs:+2:5: +2:19
+- StorageLive(_2); // scope 0 at $DIR/nrvo_simple.rs:+1:9: +1:16
+- _2 = [const 0_u8; 1024]; // scope 0 at $DIR/nrvo_simple.rs:+1:19: +1:28
++ _0 = [const 0_u8; 1024]; // scope 0 at $DIR/nrvo_simple.rs:+1:19: +1:28
+ StorageLive(_3); // scope 1 at $DIR/nrvo_simple.rs:+2:5: +2:19
+ StorageLive(_4); // scope 1 at $DIR/nrvo_simple.rs:+2:5: +2:9
+ _4 = _1; // scope 1 at $DIR/nrvo_simple.rs:+2:5: +2:9
+ StorageLive(_5); // scope 1 at $DIR/nrvo_simple.rs:+2:10: +2:18
+ StorageLive(_6); // scope 1 at $DIR/nrvo_simple.rs:+2:10: +2:18
+- _6 = &mut _2; // scope 1 at $DIR/nrvo_simple.rs:+2:10: +2:18
++ _6 = &mut _0; // scope 1 at $DIR/nrvo_simple.rs:+2:10: +2:18
+ _5 = &mut (*_6); // scope 1 at $DIR/nrvo_simple.rs:+2:10: +2:18
+ _3 = move _4(move _5) -> bb1; // scope 1 at $DIR/nrvo_simple.rs:+2:5: +2:19
}
bb1: {
- StorageDead(_5); // scope 1 at $DIR/nrvo-simple.rs:+2:18: +2:19
- StorageDead(_4); // scope 1 at $DIR/nrvo-simple.rs:+2:18: +2:19
- StorageDead(_6); // scope 1 at $DIR/nrvo-simple.rs:+2:19: +2:20
- StorageDead(_3); // scope 1 at $DIR/nrvo-simple.rs:+2:19: +2:20
-- _0 = _2; // scope 1 at $DIR/nrvo-simple.rs:+3:5: +3:8
-- StorageDead(_2); // scope 0 at $DIR/nrvo-simple.rs:+4:1: +4:2
- return; // scope 0 at $DIR/nrvo-simple.rs:+4:2: +4:2
+ StorageDead(_5); // scope 1 at $DIR/nrvo_simple.rs:+2:18: +2:19
+ StorageDead(_4); // scope 1 at $DIR/nrvo_simple.rs:+2:18: +2:19
+ StorageDead(_6); // scope 1 at $DIR/nrvo_simple.rs:+2:19: +2:20
+ StorageDead(_3); // scope 1 at $DIR/nrvo_simple.rs:+2:19: +2:20
+- _0 = _2; // scope 1 at $DIR/nrvo_simple.rs:+3:5: +3:8
+- StorageDead(_2); // scope 0 at $DIR/nrvo_simple.rs:+4:1: +4:2
+ return; // scope 0 at $DIR/nrvo_simple.rs:+4:2: +4:2
}
}
--- /dev/null
+// unit-test: RenameReturnPlace
+
+// EMIT_MIR nrvo_simple.nrvo.RenameReturnPlace.diff
+fn nrvo(init: fn(&mut [u8; 1024])) -> [u8; 1024] {
+ let mut buf = [0; 1024];
+ init(&mut buf);
+ buf
+}
+
+fn main() {
+ let _ = nrvo(|buf| { buf[4] = 4; });
+}
+++ /dev/null
-// ignore-wasm32-bare compiled with panic=abort by default
-
-
-// EMIT_MIR packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir
-fn main() {
- let mut x = Packed(Aligned(Droppy(0)));
- x.0 = Aligned(Droppy(0));
-}
-
-struct Aligned(Droppy);
-#[repr(packed)]
-struct Packed(Aligned);
-
-struct Droppy(usize);
-impl Drop for Droppy {
- fn drop(&mut self) {}
-}
// MIR for `main` after SimplifyCfg-elaborate-drops
fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:11: +0:11
- let mut _1: Packed; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14
- let mut _2: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
- let mut _3: Droppy; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
- let mut _4: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
- let mut _5: Droppy; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
- let mut _6: Aligned; // in scope 0 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
+ let mut _0: (); // return place in scope 0 at $DIR/packed_struct_drop_aligned.rs:+0:11: +0:11
+ let mut _1: Packed; // in scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:9: +1:14
+ let mut _2: Aligned; // in scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:24: +1:42
+ let mut _3: Droppy; // in scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:32: +1:41
+ let mut _4: Aligned; // in scope 0 at $DIR/packed_struct_drop_aligned.rs:+2:11: +2:29
+ let mut _5: Droppy; // in scope 0 at $DIR/packed_struct_drop_aligned.rs:+2:19: +2:28
+ let mut _6: Aligned; // in scope 0 at $DIR/packed_struct_drop_aligned.rs:+2:5: +2:8
scope 1 {
- debug x => _1; // in scope 1 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14
+ debug x => _1; // in scope 1 at $DIR/packed_struct_drop_aligned.rs:+1:9: +1:14
}
bb0: {
- StorageLive(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:9: +1:14
- StorageLive(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
- StorageLive(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
- Deinit(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
- (_3.0: usize) = const 0_usize; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:32: +1:41
- Deinit(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
- (_2.0: Droppy) = move _3; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:24: +1:42
- StorageDead(_3); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:41: +1:42
- Deinit(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43
- (_1.0: Aligned) = move _2; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:17: +1:43
- StorageDead(_2); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+1:42: +1:43
- StorageLive(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
- StorageLive(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
- Deinit(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
- (_5.0: usize) = const 0_usize; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:19: +2:28
- Deinit(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
- (_4.0: Droppy) = move _5; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:11: +2:29
- StorageDead(_5); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:28: +2:29
- StorageLive(_6); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
- _6 = move (_1.0: Aligned); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
- drop(_6) -> [return: bb4, unwind: bb3]; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
+ StorageLive(_1); // scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:9: +1:14
+ StorageLive(_2); // scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:24: +1:42
+ StorageLive(_3); // scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:32: +1:41
+ Deinit(_3); // scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:32: +1:41
+ (_3.0: usize) = const 0_usize; // scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:32: +1:41
+ Deinit(_2); // scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:24: +1:42
+ (_2.0: Droppy) = move _3; // scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:24: +1:42
+ StorageDead(_3); // scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:41: +1:42
+ Deinit(_1); // scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:17: +1:43
+ (_1.0: Aligned) = move _2; // scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:17: +1:43
+ StorageDead(_2); // scope 0 at $DIR/packed_struct_drop_aligned.rs:+1:42: +1:43
+ StorageLive(_4); // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:11: +2:29
+ StorageLive(_5); // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:19: +2:28
+ Deinit(_5); // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:19: +2:28
+ (_5.0: usize) = const 0_usize; // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:19: +2:28
+ Deinit(_4); // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:11: +2:29
+ (_4.0: Droppy) = move _5; // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:11: +2:29
+ StorageDead(_5); // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:28: +2:29
+ StorageLive(_6); // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:5: +2:8
+ _6 = move (_1.0: Aligned); // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:5: +2:8
+ drop(_6) -> [return: bb4, unwind: bb3]; // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:5: +2:8
}
bb1: {
- StorageDead(_1); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2
- return; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:2: +3:2
+ StorageDead(_1); // scope 0 at $DIR/packed_struct_drop_aligned.rs:+3:1: +3:2
+ return; // scope 0 at $DIR/packed_struct_drop_aligned.rs:+3:2: +3:2
}
bb2 (cleanup): {
- resume; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:1: +3:2
+ resume; // scope 0 at $DIR/packed_struct_drop_aligned.rs:+0:1: +3:2
}
bb3 (cleanup): {
- (_1.0: Aligned) = move _4; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
- drop(_1) -> bb2; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2
+ (_1.0: Aligned) = move _4; // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:5: +2:8
+ drop(_1) -> bb2; // scope 0 at $DIR/packed_struct_drop_aligned.rs:+3:1: +3:2
}
bb4: {
- StorageDead(_6); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
- (_1.0: Aligned) = move _4; // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:5: +2:8
- StorageDead(_4); // scope 1 at $DIR/packed-struct-drop-aligned.rs:+2:28: +2:29
- _0 = const (); // scope 0 at $DIR/packed-struct-drop-aligned.rs:+0:11: +3:2
- drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/packed-struct-drop-aligned.rs:+3:1: +3:2
+ StorageDead(_6); // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:5: +2:8
+ (_1.0: Aligned) = move _4; // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:5: +2:8
+ StorageDead(_4); // scope 1 at $DIR/packed_struct_drop_aligned.rs:+2:28: +2:29
+ _0 = const (); // scope 0 at $DIR/packed_struct_drop_aligned.rs:+0:11: +3:2
+ drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/packed_struct_drop_aligned.rs:+3:1: +3:2
}
}
--- /dev/null
+// ignore-wasm32-bare compiled with panic=abort by default
+
+
+// EMIT_MIR packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir
+fn main() {
+ let mut x = Packed(Aligned(Droppy(0)));
+ x.0 = Aligned(Droppy(0));
+}
+
+struct Aligned(Droppy);
+#[repr(packed)]
+struct Packed(Aligned);
+
+struct Droppy(usize);
+impl Drop for Droppy {
+ fn drop(&mut self) {}
+}
+++ /dev/null
-// EMIT_MIR receiver_ptr_mutability.main.mir_map.0.mir
-
-#![feature(arbitrary_self_types)]
-
-struct Test {}
-
-impl Test {
- fn x(self: *const Self) {
- println!("x called");
- }
-}
-
-fn main() {
- let ptr: *mut Test = std::ptr::null_mut();
- ptr.x();
-
- // Test autoderefs
- let ptr_ref: &&&&*mut Test = &&&&ptr;
- ptr_ref.x();
-}
+++ /dev/null
-// MIR for `main` 0 mir_map
-
-| User Type Annotations
-| 0: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*mut Test) }, span: $DIR/receiver-ptr-mutability.rs:14:14: 14:23, inferred_ty: *mut Test
-| 1: user_ty: Canonical { max_universe: U0, variables: [], value: Ty(*mut Test) }, span: $DIR/receiver-ptr-mutability.rs:14:14: 14:23, inferred_ty: *mut Test
-| 2: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }], value: Ty(&&&&*mut Test) }, span: $DIR/receiver-ptr-mutability.rs:18:18: 18:31, inferred_ty: &&&&*mut Test
-| 3: user_ty: Canonical { max_universe: U0, variables: [CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }, CanonicalVarInfo { kind: Region(U0) }], value: Ty(&&&&*mut Test) }, span: $DIR/receiver-ptr-mutability.rs:18:18: 18:31, inferred_ty: &&&&*mut Test
-|
-fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/receiver-ptr-mutability.rs:+0:11: +0:11
- let _1: *mut Test as UserTypeProjection { base: UserType(0), projs: [] }; // in scope 0 at $DIR/receiver-ptr-mutability.rs:+1:9: +1:12
- let _2: (); // in scope 0 at $DIR/receiver-ptr-mutability.rs:+2:5: +2:12
- let mut _3: *const Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:+2:5: +2:12
- let mut _4: *mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:+2:5: +2:8
- let _6: &&&&*mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:+5:34: +5:41
- let _7: &&&*mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:+5:35: +5:41
- let _8: &&*mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:+5:36: +5:41
- let _9: &*mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:+5:37: +5:41
- let _10: (); // in scope 0 at $DIR/receiver-ptr-mutability.rs:+6:5: +6:16
- let mut _11: *const Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:+6:5: +6:16
- let mut _12: *mut Test; // in scope 0 at $DIR/receiver-ptr-mutability.rs:+6:5: +6:16
- scope 1 {
- debug ptr => _1; // in scope 1 at $DIR/receiver-ptr-mutability.rs:+1:9: +1:12
- let _5: &&&&*mut Test as UserTypeProjection { base: UserType(2), projs: [] }; // in scope 1 at $DIR/receiver-ptr-mutability.rs:+5:9: +5:16
- scope 2 {
- debug ptr_ref => _5; // in scope 2 at $DIR/receiver-ptr-mutability.rs:+5:9: +5:16
- }
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/receiver-ptr-mutability.rs:+1:9: +1:12
- _1 = null_mut::<Test>() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/receiver-ptr-mutability.rs:+1:26: +1:46
- // mir::Constant
- // + span: $DIR/receiver-ptr-mutability.rs:14:26: 14:44
- // + literal: Const { ty: fn() -> *mut Test {null_mut::<Test>}, val: Value(<ZST>) }
- }
-
- bb1: {
- FakeRead(ForLet(None), _1); // scope 0 at $DIR/receiver-ptr-mutability.rs:+1:9: +1:12
- AscribeUserType(_1, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 0 at $DIR/receiver-ptr-mutability.rs:+1:14: +1:23
- StorageLive(_2); // scope 1 at $DIR/receiver-ptr-mutability.rs:+2:5: +2:12
- StorageLive(_3); // scope 1 at $DIR/receiver-ptr-mutability.rs:+2:5: +2:12
- StorageLive(_4); // scope 1 at $DIR/receiver-ptr-mutability.rs:+2:5: +2:8
- _4 = _1; // scope 1 at $DIR/receiver-ptr-mutability.rs:+2:5: +2:8
- _3 = move _4 as *const Test (Pointer(MutToConstPointer)); // scope 1 at $DIR/receiver-ptr-mutability.rs:+2:5: +2:12
- StorageDead(_4); // scope 1 at $DIR/receiver-ptr-mutability.rs:+2:7: +2:8
- _2 = Test::x(move _3) -> [return: bb2, unwind: bb4]; // scope 1 at $DIR/receiver-ptr-mutability.rs:+2:5: +2:12
- // mir::Constant
- // + span: $DIR/receiver-ptr-mutability.rs:15:9: 15:10
- // + literal: Const { ty: fn(*const Test) {Test::x}, val: Value(<ZST>) }
- }
-
- bb2: {
- StorageDead(_3); // scope 1 at $DIR/receiver-ptr-mutability.rs:+2:11: +2:12
- StorageDead(_2); // scope 1 at $DIR/receiver-ptr-mutability.rs:+2:12: +2:13
- StorageLive(_5); // scope 1 at $DIR/receiver-ptr-mutability.rs:+5:9: +5:16
- StorageLive(_6); // scope 1 at $DIR/receiver-ptr-mutability.rs:+5:34: +5:41
- StorageLive(_7); // scope 1 at $DIR/receiver-ptr-mutability.rs:+5:35: +5:41
- StorageLive(_8); // scope 1 at $DIR/receiver-ptr-mutability.rs:+5:36: +5:41
- StorageLive(_9); // scope 1 at $DIR/receiver-ptr-mutability.rs:+5:37: +5:41
- _9 = &_1; // scope 1 at $DIR/receiver-ptr-mutability.rs:+5:37: +5:41
- _8 = &_9; // scope 1 at $DIR/receiver-ptr-mutability.rs:+5:36: +5:41
- _7 = &_8; // scope 1 at $DIR/receiver-ptr-mutability.rs:+5:35: +5:41
- _6 = &_7; // scope 1 at $DIR/receiver-ptr-mutability.rs:+5:34: +5:41
- _5 = &(*_6); // scope 1 at $DIR/receiver-ptr-mutability.rs:+5:34: +5:41
- FakeRead(ForLet(None), _5); // scope 1 at $DIR/receiver-ptr-mutability.rs:+5:9: +5:16
- AscribeUserType(_5, o, UserTypeProjection { base: UserType(3), projs: [] }); // scope 1 at $DIR/receiver-ptr-mutability.rs:+5:18: +5:31
- StorageDead(_6); // scope 1 at $DIR/receiver-ptr-mutability.rs:+5:41: +5:42
- StorageLive(_10); // scope 2 at $DIR/receiver-ptr-mutability.rs:+6:5: +6:16
- StorageLive(_11); // scope 2 at $DIR/receiver-ptr-mutability.rs:+6:5: +6:16
- StorageLive(_12); // scope 2 at $DIR/receiver-ptr-mutability.rs:+6:5: +6:16
- _12 = (*(*(*(*_5)))); // scope 2 at $DIR/receiver-ptr-mutability.rs:+6:5: +6:16
- _11 = move _12 as *const Test (Pointer(MutToConstPointer)); // scope 2 at $DIR/receiver-ptr-mutability.rs:+6:5: +6:16
- StorageDead(_12); // scope 2 at $DIR/receiver-ptr-mutability.rs:+6:11: +6:12
- _10 = Test::x(move _11) -> [return: bb3, unwind: bb4]; // scope 2 at $DIR/receiver-ptr-mutability.rs:+6:5: +6:16
- // mir::Constant
- // + span: $DIR/receiver-ptr-mutability.rs:19:13: 19:14
- // + literal: Const { ty: fn(*const Test) {Test::x}, val: Value(<ZST>) }
- }
-
- bb3: {
- StorageDead(_11); // scope 2 at $DIR/receiver-ptr-mutability.rs:+6:15: +6:16
- StorageDead(_10); // scope 2 at $DIR/receiver-ptr-mutability.rs:+6:16: +6:17
- _0 = const (); // scope 0 at $DIR/receiver-ptr-mutability.rs:+0:11: +7:2
- StorageDead(_9); // scope 1 at $DIR/receiver-ptr-mutability.rs:+7:1: +7:2
- StorageDead(_8); // scope 1 at $DIR/receiver-ptr-mutability.rs:+7:1: +7:2
- StorageDead(_7); // scope 1 at $DIR/receiver-ptr-mutability.rs:+7:1: +7:2
- StorageDead(_5); // scope 1 at $DIR/receiver-ptr-mutability.rs:+7:1: +7:2
- StorageDead(_1); // scope 0 at $DIR/receiver-ptr-mutability.rs:+7:1: +7:2
- return; // scope 0 at $DIR/receiver-ptr-mutability.rs:+7:2: +7:2
- }
-
- bb4 (cleanup): {
- resume; // scope 0 at $DIR/receiver-ptr-mutability.rs:+0:1: +7:2
- }
-}
+++ /dev/null
-// This was originally a regression test for #66975 - ensure that we do not generate never typed
-// consts in codegen. We also have tests for this that catches the error, see
-// src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs.
-
-// Force generation of optimized mir for functions that do not reach codegen.
-// compile-flags: --emit mir,link
-
-#![feature(never_type)]
-
-struct PrintName<T>(T);
-
-impl<T> PrintName<T> {
- const VOID: ! = panic!();
-}
-
-// EMIT_MIR remove_never_const.no_codegen.PreCodegen.after.mir
-fn no_codegen<T>() {
- let _ = PrintName::<T>::VOID;
-}
-
-fn main() {}
// MIR for `no_codegen` after PreCodegen
fn no_codegen() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/remove-never-const.rs:+0:20: +0:20
+ let mut _0: (); // return place in scope 0 at $DIR/remove_never_const.rs:+0:20: +0:20
scope 1 {
}
bb0: {
- unreachable; // scope 0 at $DIR/remove-never-const.rs:+1:13: +1:33
+ unreachable; // scope 0 at $DIR/remove_never_const.rs:+1:13: +1:33
}
}
--- /dev/null
+// This was originally a regression test for #66975 - ensure that we do not generate never typed
+// consts in codegen. We also have tests for this that catches the error, see
+// src/test/ui/consts/const-eval/index-out-of-bounds-never-type.rs.
+
+// Force generation of optimized mir for functions that do not reach codegen.
+// compile-flags: --emit mir,link
+
+#![feature(never_type)]
+
+struct PrintName<T>(T);
+
+impl<T> PrintName<T> {
+ const VOID: ! = panic!();
+}
+
+// EMIT_MIR remove_never_const.no_codegen.PreCodegen.after.mir
+fn no_codegen<T>() {
+ let _ = PrintName::<T>::VOID;
+}
+
+fn main() {}
+++ /dev/null
-- // MIR for `try_identity` before DestinationPropagation
-+ // MIR for `try_identity` after DestinationPropagation
-
- fn try_identity(_1: std::result::Result<u32, i32>) -> std::result::Result<u32, i32> {
- debug x => _1; // in scope 0 at $DIR/simplify_try.rs:6:17: 6:18
- let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:6:41: 6:57
- let _2: u32; // in scope 0 at $DIR/simplify_try.rs:7:9: 7:10
- let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15
- let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:14
- let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
- let _6: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
- let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
- let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
- let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15
- let _10: u32; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15
- let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:8:8: 8:9
- scope 1 {
- debug y => _2; // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10
- }
- scope 2 {
- debug err => _6; // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15
- scope 3 {
- scope 7 {
- debug t => _9; // in scope 7 at $SRC_DIR/libcore/convert/mod.rs:LL:COL
- }
- scope 8 {
- debug v => _8; // in scope 8 at $SRC_DIR/libcore/result.rs:LL:COL
- let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:7:14: 7:15
- }
- }
- }
- scope 4 {
- debug val => _10; // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15
- scope 5 {
- }
- }
- scope 6 {
-- debug self => _4; // in scope 6 at $SRC_DIR/libcore/result.rs:LL:COL
-+ debug self => _0; // in scope 6 at $SRC_DIR/libcore/result.rs:LL:COL
- }
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:7:9: 7:10
-- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:7:13: 7:15
-- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:7:13: 7:14
-- _4 = _1; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14
-- _3 = move _4; // scope 6 at $SRC_DIR/libcore/result.rs:LL:COL
-- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-+ nop; // scope 0 at $DIR/simplify_try.rs:7:13: 7:15
-+ nop; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14
-+ _0 = _1; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14
-+ nop; // scope 6 at $SRC_DIR/libcore/result.rs:LL:COL
-+ nop; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
-+ _5 = discriminant(_0); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
- goto -> bb1; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15
- }
-
- bb1: {
-- _0 = move _3; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10
-- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:7:15: 7:16
-+ nop; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10
-+ nop; // scope 0 at $DIR/simplify_try.rs:7:15: 7:16
- StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:9:1: 9:2
- goto -> bb2; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2
- }
-
- bb2: {
- return; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2
- }
- }
-
+++ /dev/null
-// Test that we don't generate unnecessarily large MIR for very simple matches
-
-
-// EMIT_MIR simple_match.match_bool.mir_map.0.mir
-fn match_bool(x: bool) -> usize {
- match x {
- true => 10,
- _ => 20,
- }
-}
-
-fn main() {}
+++ /dev/null
-// MIR for `match_bool` 0 mir_map
-
-fn match_bool(_1: bool) -> usize {
- debug x => _1; // in scope 0 at $DIR/simple-match.rs:+0:15: +0:16
- let mut _0: usize; // return place in scope 0 at $DIR/simple-match.rs:+0:27: +0:32
-
- bb0: {
- FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/simple-match.rs:+1:11: +1:12
- switchInt(_1) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/simple-match.rs:+1:5: +1:12
- }
-
- bb1: {
- falseEdge -> [real: bb3, imaginary: bb2]; // scope 0 at $DIR/simple-match.rs:+2:9: +2:13
- }
-
- bb2: {
- _0 = const 20_usize; // scope 0 at $DIR/simple-match.rs:+3:14: +3:16
- goto -> bb4; // scope 0 at $DIR/simple-match.rs:+3:14: +3:16
- }
-
- bb3: {
- _0 = const 10_usize; // scope 0 at $DIR/simple-match.rs:+2:17: +2:19
- goto -> bb4; // scope 0 at $DIR/simple-match.rs:+2:17: +2:19
- }
-
- bb4: {
- return; // scope 0 at $DIR/simple-match.rs:+5:2: +5:2
- }
-}
+++ /dev/null
-// Checks that `SimplifyArmIdentity` is not applied if enums have incompatible layouts.
-// Regression test for issue #66856.
-//
-// compile-flags: -Zmir-opt-level=3
-// EMIT_MIR_FOR_EACH_BIT_WIDTH
-
-// This pass is broken since deaggregation changed
-// ignore-test
-
-enum Src {
- Foo(u8),
- Bar,
-}
-
-enum Dst {
- Foo(u8),
-}
-
-// EMIT_MIR simplify_arm_identity.main.SimplifyArmIdentity.diff
-fn main() {
- let e: Src = Src::Foo(0);
- let _: Dst = match e {
- Src::Foo(x) => Dst::Foo(x),
- Src::Bar => Dst::Foo(0),
- };
-}
+++ /dev/null
-// compile-flags: -Z mir-opt-level=3 -Zunsound-mir-opts
-// EMIT_MIR simplify_arm.id.SimplifyArmIdentity.diff
-// EMIT_MIR simplify_arm.id.SimplifyBranchSame.diff
-// EMIT_MIR simplify_arm.id_result.SimplifyArmIdentity.diff
-// EMIT_MIR simplify_arm.id_result.SimplifyBranchSame.diff
-// EMIT_MIR simplify_arm.id_try.SimplifyArmIdentity.diff
-// EMIT_MIR simplify_arm.id_try.SimplifyBranchSame.diff
-
-// This pass is broken since deaggregation changed
-// ignore-test
-
-fn id(o: Option<u8>) -> Option<u8> {
- match o {
- Some(v) => Some(v),
- None => None,
- }
-}
-
-fn id_result(r: Result<u8, i32>) -> Result<u8, i32> {
- match r {
- Ok(x) => Ok(x),
- Err(y) => Err(y),
- }
-}
-
-fn into_result<T, E>(r: Result<T, E>) -> Result<T, E> {
- r
-}
-
-fn from_error<T, E>(e: E) -> Result<T, E> {
- Err(e)
-}
-
-// This was written to the `?` from `try_trait`, but `try_trait_v2` uses a different structure,
-// so the relevant desugar is copied inline in order to keep the test testing the same thing.
-// FIXME(#85133): while this might be useful for `r#try!`, it would be nice to have a MIR
-// optimization that picks up the `?` desugaring, as `SimplifyArmIdentity` does not.
-fn id_try(r: Result<u8, i32>) -> Result<u8, i32> {
- let x = match into_result(r) {
- Err(e) => return from_error(From::from(e)),
- Ok(v) => v,
- };
- Ok(x)
-}
-
-fn main() {
- id(None);
- id_result(Ok(4));
- id_try(Ok(4));
-}
+++ /dev/null
-// compile-flags: -Zmir-opt-level=1
-
-fn foo<T>() {
- if let (Some(a), None) = (Option::<u8>::None, Option::<T>::None) {
- if a > 42u8 {
-
- }
- }
-}
-
-fn main() {
- foo::<()>();
-}
-
-// EMIT_MIR simplify_locals_fixedpoint.foo.SimplifyLocals.diff
+++ /dev/null
-// unit-test: SimplifyLocals
-// compile-flags: -C overflow-checks=no
-
-fn use_zst(_: ((), ())) {}
-
-struct Temp {
- x: u8,
-}
-
-fn use_u8(_: u8) {}
-
-// EMIT_MIR simplify_locals_removes_unused_consts.main.SimplifyLocals.diff
-fn main() {
- let ((), ()) = ((), ());
- use_zst(((), ()));
-
- use_u8((Temp { x: 40 }).x + 2);
-}
+++ /dev/null
-// unit-test: SimplifyLocals
-
-fn map(x: Option<Box<()>>) -> Option<Box<()>> {
- match x {
- None => None,
- Some(x) => Some(x),
- }
-}
-
-fn main() {
- map(None);
-}
-
-// EMIT_MIR simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff
+++ /dev/null
-// unit-test: SimplifyLocals
-
-
-#![feature(thread_local)]
-
-#[derive(Copy, Clone)]
-enum E {
- A,
- B,
-}
-
-// EMIT_MIR simplify_locals.c.SimplifyLocals.diff
-fn c() {
- let bytes = [0u8; 10];
- // Unused cast
- let _: &[u8] = &bytes;
-}
-
-// EMIT_MIR simplify_locals.d1.SimplifyLocals.diff
-fn d1() {
- // Unused set discriminant
- let _ = E::A;
-}
-
-// EMIT_MIR simplify_locals.d2.SimplifyLocals.diff
-fn d2() {
- // Unused set discriminant
- {(10, E::A)}.1 = E::B;
-}
-
-// EMIT_MIR simplify_locals.r.SimplifyLocals.diff
-fn r() {
- let mut a = 1;
- // Unused references
- let _ = &a;
- let _ = &mut a;
-}
-
-#[thread_local] static mut X: u32 = 0;
-
-// EMIT_MIR simplify_locals.t1.SimplifyLocals.diff
-fn t1() {
- // Unused thread local
- unsafe { X };
-}
-
-// EMIT_MIR simplify_locals.t2.SimplifyLocals.diff
-fn t2() {
- // Unused thread local
- unsafe { &mut X };
-}
-
-// EMIT_MIR simplify_locals.t3.SimplifyLocals.diff
-fn t3() {
- // Unused thread local
- unsafe { *&mut X };
-}
-
-// EMIT_MIR simplify_locals.t4.SimplifyLocals.diff
-fn t4() -> u32 {
- // Used thread local
- unsafe { X + 1 }
-}
-
-// EMIT_MIR simplify_locals.expose_addr.SimplifyLocals.diff
-fn expose_addr(p: *const usize) {
- // Used pointer to address cast. Has a side effect of exposing the provenance.
- p as usize;
-}
-
-fn main() {
- c();
- d1();
- d2();
- r();
- t1();
- t2();
- t3();
- t4();
- expose_addr(&0);
-}
--- /dev/null
+// compile-flags: -Z mir-opt-level=3 -Zunsound-mir-opts
+// EMIT_MIR simplify_arm.id.SimplifyArmIdentity.diff
+// EMIT_MIR simplify_arm.id.SimplifyBranchSame.diff
+// EMIT_MIR simplify_arm.id_result.SimplifyArmIdentity.diff
+// EMIT_MIR simplify_arm.id_result.SimplifyBranchSame.diff
+// EMIT_MIR simplify_arm.id_try.SimplifyArmIdentity.diff
+// EMIT_MIR simplify_arm.id_try.SimplifyBranchSame.diff
+
+// This pass is broken since deaggregation changed
+// ignore-test
+
+fn id(o: Option<u8>) -> Option<u8> {
+ match o {
+ Some(v) => Some(v),
+ None => None,
+ }
+}
+
+fn id_result(r: Result<u8, i32>) -> Result<u8, i32> {
+ match r {
+ Ok(x) => Ok(x),
+ Err(y) => Err(y),
+ }
+}
+
+fn into_result<T, E>(r: Result<T, E>) -> Result<T, E> {
+ r
+}
+
+fn from_error<T, E>(e: E) -> Result<T, E> {
+ Err(e)
+}
+
+// This was written to the `?` from `try_trait`, but `try_trait_v2` uses a different structure,
+// so the relevant desugar is copied inline in order to keep the test testing the same thing.
+// FIXME(#85133): while this might be useful for `r#try!`, it would be nice to have a MIR
+// optimization that picks up the `?` desugaring, as `SimplifyArmIdentity` does not.
+fn id_try(r: Result<u8, i32>) -> Result<u8, i32> {
+ let x = match into_result(r) {
+ Err(e) => return from_error(From::from(e)),
+ Ok(v) => v,
+ };
+ Ok(x)
+}
+
+fn main() {
+ id(None);
+ id_result(Ok(4));
+ id_try(Ok(4));
+}
--- /dev/null
+// Checks that `SimplifyArmIdentity` is not applied if enums have incompatible layouts.
+// Regression test for issue #66856.
+//
+// compile-flags: -Zmir-opt-level=3
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
+// This pass is broken since deaggregation changed
+// ignore-test
+
+enum Src {
+ Foo(u8),
+ Bar,
+}
+
+enum Dst {
+ Foo(u8),
+}
+
+// EMIT_MIR simplify_arm_identity.main.SimplifyArmIdentity.diff
+fn main() {
+ let e: Src = Src::Foo(0);
+ let _: Dst = match e {
+ Src::Foo(x) => Dst::Foo(x),
+ Src::Bar => Dst::Foo(0),
+ };
+}
+ // MIR for `c` after SimplifyLocals
fn c() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/simplify-locals.rs:+0:8: +0:8
- let _1: [u8; 10]; // in scope 0 at $DIR/simplify-locals.rs:+1:9: +1:14
-- let mut _2: &[u8]; // in scope 0 at $DIR/simplify-locals.rs:+3:20: +3:26
-- let mut _3: &[u8; 10]; // in scope 0 at $DIR/simplify-locals.rs:+3:20: +3:26
-- let _4: &[u8; 10]; // in scope 0 at $DIR/simplify-locals.rs:+3:20: +3:26
+ let mut _0: (); // return place in scope 0 at $DIR/simplify_locals.rs:+0:8: +0:8
+ let _1: [u8; 10]; // in scope 0 at $DIR/simplify_locals.rs:+1:9: +1:14
+- let mut _2: &[u8]; // in scope 0 at $DIR/simplify_locals.rs:+3:20: +3:26
+- let mut _3: &[u8; 10]; // in scope 0 at $DIR/simplify_locals.rs:+3:20: +3:26
+- let _4: &[u8; 10]; // in scope 0 at $DIR/simplify_locals.rs:+3:20: +3:26
scope 1 {
- debug bytes => _1; // in scope 1 at $DIR/simplify-locals.rs:+1:9: +1:14
+ debug bytes => _1; // in scope 1 at $DIR/simplify_locals.rs:+1:9: +1:14
scope 2 {
}
}
bb0: {
- StorageLive(_1); // scope 0 at $DIR/simplify-locals.rs:+1:9: +1:14
- _1 = [const 0_u8; 10]; // scope 0 at $DIR/simplify-locals.rs:+1:17: +1:26
-- StorageLive(_2); // scope 1 at $DIR/simplify-locals.rs:+3:20: +3:26
-- StorageLive(_3); // scope 1 at $DIR/simplify-locals.rs:+3:20: +3:26
-- StorageLive(_4); // scope 1 at $DIR/simplify-locals.rs:+3:20: +3:26
-- _4 = &_1; // scope 1 at $DIR/simplify-locals.rs:+3:20: +3:26
-- _3 = &(*_4); // scope 1 at $DIR/simplify-locals.rs:+3:20: +3:26
-- _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 1 at $DIR/simplify-locals.rs:+3:20: +3:26
-- StorageDead(_3); // scope 1 at $DIR/simplify-locals.rs:+3:25: +3:26
-- StorageDead(_4); // scope 1 at $DIR/simplify-locals.rs:+3:26: +3:27
-- StorageDead(_2); // scope 1 at $DIR/simplify-locals.rs:+3:26: +3:27
- _0 = const (); // scope 0 at $DIR/simplify-locals.rs:+0:8: +4:2
- StorageDead(_1); // scope 0 at $DIR/simplify-locals.rs:+4:1: +4:2
- return; // scope 0 at $DIR/simplify-locals.rs:+4:2: +4:2
+ StorageLive(_1); // scope 0 at $DIR/simplify_locals.rs:+1:9: +1:14
+ _1 = [const 0_u8; 10]; // scope 0 at $DIR/simplify_locals.rs:+1:17: +1:26
+- StorageLive(_2); // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
+- StorageLive(_3); // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
+- StorageLive(_4); // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
+- _4 = &_1; // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
+- _3 = &(*_4); // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
+- _2 = move _3 as &[u8] (Pointer(Unsize)); // scope 1 at $DIR/simplify_locals.rs:+3:20: +3:26
+- StorageDead(_3); // scope 1 at $DIR/simplify_locals.rs:+3:25: +3:26
+- StorageDead(_4); // scope 1 at $DIR/simplify_locals.rs:+3:26: +3:27
+- StorageDead(_2); // scope 1 at $DIR/simplify_locals.rs:+3:26: +3:27
+ _0 = const (); // scope 0 at $DIR/simplify_locals.rs:+0:8: +4:2
+ StorageDead(_1); // scope 0 at $DIR/simplify_locals.rs:+4:1: +4:2
+ return; // scope 0 at $DIR/simplify_locals.rs:+4:2: +4:2
}
}
+ // MIR for `d1` after SimplifyLocals
fn d1() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/simplify-locals.rs:+0:9: +0:9
-- let mut _1: E; // in scope 0 at $DIR/simplify-locals.rs:+2:13: +2:17
+ let mut _0: (); // return place in scope 0 at $DIR/simplify_locals.rs:+0:9: +0:9
+- let mut _1: E; // in scope 0 at $DIR/simplify_locals.rs:+2:13: +2:17
scope 1 {
}
bb0: {
-- StorageLive(_1); // scope 0 at $DIR/simplify-locals.rs:+2:13: +2:17
-- Deinit(_1); // scope 0 at $DIR/simplify-locals.rs:+2:13: +2:17
-- discriminant(_1) = 0; // scope 0 at $DIR/simplify-locals.rs:+2:13: +2:17
-- StorageDead(_1); // scope 0 at $DIR/simplify-locals.rs:+2:17: +2:18
- _0 = const (); // scope 0 at $DIR/simplify-locals.rs:+0:9: +3:2
- return; // scope 0 at $DIR/simplify-locals.rs:+3:2: +3:2
+- StorageLive(_1); // scope 0 at $DIR/simplify_locals.rs:+2:13: +2:17
+- Deinit(_1); // scope 0 at $DIR/simplify_locals.rs:+2:13: +2:17
+- discriminant(_1) = 0; // scope 0 at $DIR/simplify_locals.rs:+2:13: +2:17
+- StorageDead(_1); // scope 0 at $DIR/simplify_locals.rs:+2:17: +2:18
+ _0 = const (); // scope 0 at $DIR/simplify_locals.rs:+0:9: +3:2
+ return; // scope 0 at $DIR/simplify_locals.rs:+3:2: +3:2
}
}
+ // MIR for `d2` after SimplifyLocals
fn d2() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/simplify-locals.rs:+0:9: +0:9
-- let mut _1: E; // in scope 0 at $DIR/simplify-locals.rs:+2:22: +2:26
-- let mut _2: (i32, E); // in scope 0 at $DIR/simplify-locals.rs:+2:5: +2:17
-- let mut _3: E; // in scope 0 at $DIR/simplify-locals.rs:+2:11: +2:15
+ let mut _0: (); // return place in scope 0 at $DIR/simplify_locals.rs:+0:9: +0:9
+- let mut _1: E; // in scope 0 at $DIR/simplify_locals.rs:+2:22: +2:26
+- let mut _2: (i32, E); // in scope 0 at $DIR/simplify_locals.rs:+2:5: +2:17
+- let mut _3: E; // in scope 0 at $DIR/simplify_locals.rs:+2:11: +2:15
bb0: {
-- StorageLive(_1); // scope 0 at $DIR/simplify-locals.rs:+2:22: +2:26
-- Deinit(_1); // scope 0 at $DIR/simplify-locals.rs:+2:22: +2:26
-- discriminant(_1) = 1; // scope 0 at $DIR/simplify-locals.rs:+2:22: +2:26
-- StorageLive(_2); // scope 0 at $DIR/simplify-locals.rs:+2:5: +2:17
-- StorageLive(_3); // scope 0 at $DIR/simplify-locals.rs:+2:11: +2:15
-- Deinit(_3); // scope 0 at $DIR/simplify-locals.rs:+2:11: +2:15
-- discriminant(_3) = 0; // scope 0 at $DIR/simplify-locals.rs:+2:11: +2:15
-- Deinit(_2); // scope 0 at $DIR/simplify-locals.rs:+2:6: +2:16
-- (_2.0: i32) = const 10_i32; // scope 0 at $DIR/simplify-locals.rs:+2:6: +2:16
-- (_2.1: E) = move _3; // scope 0 at $DIR/simplify-locals.rs:+2:6: +2:16
-- StorageDead(_3); // scope 0 at $DIR/simplify-locals.rs:+2:15: +2:16
-- (_2.1: E) = move _1; // scope 0 at $DIR/simplify-locals.rs:+2:5: +2:26
-- StorageDead(_1); // scope 0 at $DIR/simplify-locals.rs:+2:25: +2:26
-- StorageDead(_2); // scope 0 at $DIR/simplify-locals.rs:+2:26: +2:27
- _0 = const (); // scope 0 at $DIR/simplify-locals.rs:+0:9: +3:2
- return; // scope 0 at $DIR/simplify-locals.rs:+3:2: +3:2
+- StorageLive(_1); // scope 0 at $DIR/simplify_locals.rs:+2:22: +2:26
+- Deinit(_1); // scope 0 at $DIR/simplify_locals.rs:+2:22: +2:26
+- discriminant(_1) = 1; // scope 0 at $DIR/simplify_locals.rs:+2:22: +2:26
+- StorageLive(_2); // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:17
+- StorageLive(_3); // scope 0 at $DIR/simplify_locals.rs:+2:11: +2:15
+- Deinit(_3); // scope 0 at $DIR/simplify_locals.rs:+2:11: +2:15
+- discriminant(_3) = 0; // scope 0 at $DIR/simplify_locals.rs:+2:11: +2:15
+- Deinit(_2); // scope 0 at $DIR/simplify_locals.rs:+2:6: +2:16
+- (_2.0: i32) = const 10_i32; // scope 0 at $DIR/simplify_locals.rs:+2:6: +2:16
+- (_2.1: E) = move _3; // scope 0 at $DIR/simplify_locals.rs:+2:6: +2:16
+- StorageDead(_3); // scope 0 at $DIR/simplify_locals.rs:+2:15: +2:16
+- (_2.1: E) = move _1; // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:26
+- StorageDead(_1); // scope 0 at $DIR/simplify_locals.rs:+2:25: +2:26
+- StorageDead(_2); // scope 0 at $DIR/simplify_locals.rs:+2:26: +2:27
+ _0 = const (); // scope 0 at $DIR/simplify_locals.rs:+0:9: +3:2
+ return; // scope 0 at $DIR/simplify_locals.rs:+3:2: +3:2
}
}
+ // MIR for `expose_addr` after SimplifyLocals
fn expose_addr(_1: *const usize) -> () {
- debug p => _1; // in scope 0 at $DIR/simplify-locals.rs:+0:16: +0:17
- let mut _0: (); // return place in scope 0 at $DIR/simplify-locals.rs:+0:33: +0:33
- let _2: usize; // in scope 0 at $DIR/simplify-locals.rs:+2:5: +2:15
- let mut _3: *const usize; // in scope 0 at $DIR/simplify-locals.rs:+2:5: +2:6
+ debug p => _1; // in scope 0 at $DIR/simplify_locals.rs:+0:16: +0:17
+ let mut _0: (); // return place in scope 0 at $DIR/simplify_locals.rs:+0:33: +0:33
+ let _2: usize; // in scope 0 at $DIR/simplify_locals.rs:+2:5: +2:15
+ let mut _3: *const usize; // in scope 0 at $DIR/simplify_locals.rs:+2:5: +2:6
bb0: {
- StorageLive(_2); // scope 0 at $DIR/simplify-locals.rs:+2:5: +2:15
- StorageLive(_3); // scope 0 at $DIR/simplify-locals.rs:+2:5: +2:6
- _3 = _1; // scope 0 at $DIR/simplify-locals.rs:+2:5: +2:6
- _2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/simplify-locals.rs:+2:5: +2:15
- StorageDead(_3); // scope 0 at $DIR/simplify-locals.rs:+2:14: +2:15
- StorageDead(_2); // scope 0 at $DIR/simplify-locals.rs:+2:15: +2:16
- _0 = const (); // scope 0 at $DIR/simplify-locals.rs:+0:33: +3:2
- return; // scope 0 at $DIR/simplify-locals.rs:+3:2: +3:2
+ StorageLive(_2); // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:15
+ StorageLive(_3); // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:6
+ _3 = _1; // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:6
+ _2 = move _3 as usize (PointerExposeAddress); // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:15
+ StorageDead(_3); // scope 0 at $DIR/simplify_locals.rs:+2:14: +2:15
+ StorageDead(_2); // scope 0 at $DIR/simplify_locals.rs:+2:15: +2:16
+ _0 = const (); // scope 0 at $DIR/simplify_locals.rs:+0:33: +3:2
+ return; // scope 0 at $DIR/simplify_locals.rs:+3:2: +3:2
}
}
+ // MIR for `r` after SimplifyLocals
fn r() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/simplify-locals.rs:+0:8: +0:8
- let mut _1: i32; // in scope 0 at $DIR/simplify-locals.rs:+1:9: +1:14
-- let mut _2: &i32; // in scope 0 at $DIR/simplify-locals.rs:+3:13: +3:15
-- let mut _3: &mut i32; // in scope 0 at $DIR/simplify-locals.rs:+4:13: +4:19
+ let mut _0: (); // return place in scope 0 at $DIR/simplify_locals.rs:+0:8: +0:8
+ let mut _1: i32; // in scope 0 at $DIR/simplify_locals.rs:+1:9: +1:14
+- let mut _2: &i32; // in scope 0 at $DIR/simplify_locals.rs:+3:13: +3:15
+- let mut _3: &mut i32; // in scope 0 at $DIR/simplify_locals.rs:+4:13: +4:19
scope 1 {
- debug a => _1; // in scope 1 at $DIR/simplify-locals.rs:+1:9: +1:14
+ debug a => _1; // in scope 1 at $DIR/simplify_locals.rs:+1:9: +1:14
scope 2 {
scope 3 {
}
}
bb0: {
- StorageLive(_1); // scope 0 at $DIR/simplify-locals.rs:+1:9: +1:14
- _1 = const 1_i32; // scope 0 at $DIR/simplify-locals.rs:+1:17: +1:18
-- StorageLive(_2); // scope 1 at $DIR/simplify-locals.rs:+3:13: +3:15
-- _2 = &_1; // scope 1 at $DIR/simplify-locals.rs:+3:13: +3:15
-- StorageDead(_2); // scope 1 at $DIR/simplify-locals.rs:+3:15: +3:16
-- StorageLive(_3); // scope 2 at $DIR/simplify-locals.rs:+4:13: +4:19
-- _3 = &mut _1; // scope 2 at $DIR/simplify-locals.rs:+4:13: +4:19
-- StorageDead(_3); // scope 2 at $DIR/simplify-locals.rs:+4:19: +4:20
- _0 = const (); // scope 0 at $DIR/simplify-locals.rs:+0:8: +5:2
- StorageDead(_1); // scope 0 at $DIR/simplify-locals.rs:+5:1: +5:2
- return; // scope 0 at $DIR/simplify-locals.rs:+5:2: +5:2
+ StorageLive(_1); // scope 0 at $DIR/simplify_locals.rs:+1:9: +1:14
+ _1 = const 1_i32; // scope 0 at $DIR/simplify_locals.rs:+1:17: +1:18
+- StorageLive(_2); // scope 1 at $DIR/simplify_locals.rs:+3:13: +3:15
+- _2 = &_1; // scope 1 at $DIR/simplify_locals.rs:+3:13: +3:15
+- StorageDead(_2); // scope 1 at $DIR/simplify_locals.rs:+3:15: +3:16
+- StorageLive(_3); // scope 2 at $DIR/simplify_locals.rs:+4:13: +4:19
+- _3 = &mut _1; // scope 2 at $DIR/simplify_locals.rs:+4:13: +4:19
+- StorageDead(_3); // scope 2 at $DIR/simplify_locals.rs:+4:19: +4:20
+ _0 = const (); // scope 0 at $DIR/simplify_locals.rs:+0:8: +5:2
+ StorageDead(_1); // scope 0 at $DIR/simplify_locals.rs:+5:1: +5:2
+ return; // scope 0 at $DIR/simplify_locals.rs:+5:2: +5:2
}
}
--- /dev/null
+// unit-test: SimplifyLocals
+
+
+#![feature(thread_local)]
+
+#[derive(Copy, Clone)]
+enum E {
+ A,
+ B,
+}
+
+// EMIT_MIR simplify_locals.c.SimplifyLocals.diff
+fn c() {
+ let bytes = [0u8; 10];
+ // Unused cast
+ let _: &[u8] = &bytes;
+}
+
+// EMIT_MIR simplify_locals.d1.SimplifyLocals.diff
+fn d1() {
+ // Unused set discriminant
+ let _ = E::A;
+}
+
+// EMIT_MIR simplify_locals.d2.SimplifyLocals.diff
+fn d2() {
+ // Unused set discriminant
+ {(10, E::A)}.1 = E::B;
+}
+
+// EMIT_MIR simplify_locals.r.SimplifyLocals.diff
+fn r() {
+ let mut a = 1;
+ // Unused references
+ let _ = &a;
+ let _ = &mut a;
+}
+
+#[thread_local] static mut X: u32 = 0;
+
+// EMIT_MIR simplify_locals.t1.SimplifyLocals.diff
+fn t1() {
+ // Unused thread local
+ unsafe { X };
+}
+
+// EMIT_MIR simplify_locals.t2.SimplifyLocals.diff
+fn t2() {
+ // Unused thread local
+ unsafe { &mut X };
+}
+
+// EMIT_MIR simplify_locals.t3.SimplifyLocals.diff
+fn t3() {
+ // Unused thread local
+ unsafe { *&mut X };
+}
+
+// EMIT_MIR simplify_locals.t4.SimplifyLocals.diff
+fn t4() -> u32 {
+ // Used thread local
+ unsafe { X + 1 }
+}
+
+// EMIT_MIR simplify_locals.expose_addr.SimplifyLocals.diff
+fn expose_addr(p: *const usize) {
+ // Used pointer to address cast. Has a side effect of exposing the provenance.
+ p as usize;
+}
+
+fn main() {
+ c();
+ d1();
+ d2();
+ r();
+ t1();
+ t2();
+ t3();
+ t4();
+ expose_addr(&0);
+}
+ // MIR for `t1` after SimplifyLocals
fn t1() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/simplify-locals.rs:+0:9: +0:9
-- let _1: u32; // in scope 0 at $DIR/simplify-locals.rs:+2:14: +2:15
-- let mut _2: *mut u32; // in scope 0 at $DIR/simplify-locals.rs:+2:14: +2:15
+ let mut _0: (); // return place in scope 0 at $DIR/simplify_locals.rs:+0:9: +0:9
+- let _1: u32; // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:15
+- let mut _2: *mut u32; // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:15
scope 1 {
}
bb0: {
-- StorageLive(_1); // scope 0 at $DIR/simplify-locals.rs:+2:5: +2:17
-- StorageLive(_2); // scope 1 at $DIR/simplify-locals.rs:+2:14: +2:15
-- _2 = &/*tls*/ mut X; // scope 1 at $DIR/simplify-locals.rs:+2:14: +2:15
-- _1 = (*_2); // scope 1 at $DIR/simplify-locals.rs:+2:14: +2:15
-- StorageDead(_2); // scope 0 at $DIR/simplify-locals.rs:+2:17: +2:18
-- StorageDead(_1); // scope 0 at $DIR/simplify-locals.rs:+2:17: +2:18
- _0 = const (); // scope 0 at $DIR/simplify-locals.rs:+0:9: +3:2
- return; // scope 0 at $DIR/simplify-locals.rs:+3:2: +3:2
+- StorageLive(_1); // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:17
+- StorageLive(_2); // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
+- _2 = &/*tls*/ mut X; // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
+- _1 = (*_2); // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
+- StorageDead(_2); // scope 0 at $DIR/simplify_locals.rs:+2:17: +2:18
+- StorageDead(_1); // scope 0 at $DIR/simplify_locals.rs:+2:17: +2:18
+ _0 = const (); // scope 0 at $DIR/simplify_locals.rs:+0:9: +3:2
+ return; // scope 0 at $DIR/simplify_locals.rs:+3:2: +3:2
}
}
+ // MIR for `t2` after SimplifyLocals
fn t2() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/simplify-locals.rs:+0:9: +0:9
-- let _1: &mut u32; // in scope 0 at $DIR/simplify-locals.rs:+2:14: +2:20
-- let mut _2: *mut u32; // in scope 0 at $DIR/simplify-locals.rs:+2:19: +2:20
+ let mut _0: (); // return place in scope 0 at $DIR/simplify_locals.rs:+0:9: +0:9
+- let _1: &mut u32; // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:20
+- let mut _2: *mut u32; // in scope 0 at $DIR/simplify_locals.rs:+2:19: +2:20
scope 1 {
}
bb0: {
-- StorageLive(_1); // scope 0 at $DIR/simplify-locals.rs:+2:5: +2:22
-- StorageLive(_2); // scope 1 at $DIR/simplify-locals.rs:+2:19: +2:20
-- _2 = &/*tls*/ mut X; // scope 1 at $DIR/simplify-locals.rs:+2:19: +2:20
-- _1 = &mut (*_2); // scope 1 at $DIR/simplify-locals.rs:+2:14: +2:20
-- StorageDead(_2); // scope 0 at $DIR/simplify-locals.rs:+2:22: +2:23
-- StorageDead(_1); // scope 0 at $DIR/simplify-locals.rs:+2:22: +2:23
- _0 = const (); // scope 0 at $DIR/simplify-locals.rs:+0:9: +3:2
- return; // scope 0 at $DIR/simplify-locals.rs:+3:2: +3:2
+- StorageLive(_1); // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:22
+- StorageLive(_2); // scope 1 at $DIR/simplify_locals.rs:+2:19: +2:20
+- _2 = &/*tls*/ mut X; // scope 1 at $DIR/simplify_locals.rs:+2:19: +2:20
+- _1 = &mut (*_2); // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:20
+- StorageDead(_2); // scope 0 at $DIR/simplify_locals.rs:+2:22: +2:23
+- StorageDead(_1); // scope 0 at $DIR/simplify_locals.rs:+2:22: +2:23
+ _0 = const (); // scope 0 at $DIR/simplify_locals.rs:+0:9: +3:2
+ return; // scope 0 at $DIR/simplify_locals.rs:+3:2: +3:2
}
}
+ // MIR for `t3` after SimplifyLocals
fn t3() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/simplify-locals.rs:+0:9: +0:9
-- let _1: u32; // in scope 0 at $DIR/simplify-locals.rs:+2:14: +2:21
-- let mut _2: &mut u32; // in scope 0 at $DIR/simplify-locals.rs:+2:15: +2:21
-- let mut _3: *mut u32; // in scope 0 at $DIR/simplify-locals.rs:+2:20: +2:21
+ let mut _0: (); // return place in scope 0 at $DIR/simplify_locals.rs:+0:9: +0:9
+- let _1: u32; // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:21
+- let mut _2: &mut u32; // in scope 0 at $DIR/simplify_locals.rs:+2:15: +2:21
+- let mut _3: *mut u32; // in scope 0 at $DIR/simplify_locals.rs:+2:20: +2:21
scope 1 {
}
bb0: {
-- StorageLive(_1); // scope 0 at $DIR/simplify-locals.rs:+2:5: +2:23
-- StorageLive(_2); // scope 1 at $DIR/simplify-locals.rs:+2:15: +2:21
-- StorageLive(_3); // scope 1 at $DIR/simplify-locals.rs:+2:20: +2:21
-- _3 = &/*tls*/ mut X; // scope 1 at $DIR/simplify-locals.rs:+2:20: +2:21
-- _2 = &mut (*_3); // scope 1 at $DIR/simplify-locals.rs:+2:15: +2:21
-- _1 = (*_2); // scope 1 at $DIR/simplify-locals.rs:+2:14: +2:21
-- StorageDead(_3); // scope 0 at $DIR/simplify-locals.rs:+2:23: +2:24
-- StorageDead(_2); // scope 0 at $DIR/simplify-locals.rs:+2:23: +2:24
-- StorageDead(_1); // scope 0 at $DIR/simplify-locals.rs:+2:23: +2:24
- _0 = const (); // scope 0 at $DIR/simplify-locals.rs:+0:9: +3:2
- return; // scope 0 at $DIR/simplify-locals.rs:+3:2: +3:2
+- StorageLive(_1); // scope 0 at $DIR/simplify_locals.rs:+2:5: +2:23
+- StorageLive(_2); // scope 1 at $DIR/simplify_locals.rs:+2:15: +2:21
+- StorageLive(_3); // scope 1 at $DIR/simplify_locals.rs:+2:20: +2:21
+- _3 = &/*tls*/ mut X; // scope 1 at $DIR/simplify_locals.rs:+2:20: +2:21
+- _2 = &mut (*_3); // scope 1 at $DIR/simplify_locals.rs:+2:15: +2:21
+- _1 = (*_2); // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:21
+- StorageDead(_3); // scope 0 at $DIR/simplify_locals.rs:+2:23: +2:24
+- StorageDead(_2); // scope 0 at $DIR/simplify_locals.rs:+2:23: +2:24
+- StorageDead(_1); // scope 0 at $DIR/simplify_locals.rs:+2:23: +2:24
+ _0 = const (); // scope 0 at $DIR/simplify_locals.rs:+0:9: +3:2
+ return; // scope 0 at $DIR/simplify_locals.rs:+3:2: +3:2
}
}
+ // MIR for `t4` after SimplifyLocals
fn t4() -> u32 {
- let mut _0: u32; // return place in scope 0 at $DIR/simplify-locals.rs:+0:12: +0:15
- let mut _1: u32; // in scope 0 at $DIR/simplify-locals.rs:+2:14: +2:15
- let mut _2: *mut u32; // in scope 0 at $DIR/simplify-locals.rs:+2:14: +2:15
+ let mut _0: u32; // return place in scope 0 at $DIR/simplify_locals.rs:+0:12: +0:15
+ let mut _1: u32; // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:15
+ let mut _2: *mut u32; // in scope 0 at $DIR/simplify_locals.rs:+2:14: +2:15
scope 1 {
}
bb0: {
- StorageLive(_1); // scope 1 at $DIR/simplify-locals.rs:+2:14: +2:15
- StorageLive(_2); // scope 1 at $DIR/simplify-locals.rs:+2:14: +2:15
- _2 = &/*tls*/ mut X; // scope 1 at $DIR/simplify-locals.rs:+2:14: +2:15
- _1 = (*_2); // scope 1 at $DIR/simplify-locals.rs:+2:14: +2:15
- _0 = Add(move _1, const 1_u32); // scope 1 at $DIR/simplify-locals.rs:+2:14: +2:19
- StorageDead(_1); // scope 1 at $DIR/simplify-locals.rs:+2:18: +2:19
- StorageDead(_2); // scope 0 at $DIR/simplify-locals.rs:+3:1: +3:2
- return; // scope 0 at $DIR/simplify-locals.rs:+3:2: +3:2
+ StorageLive(_1); // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
+ StorageLive(_2); // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
+ _2 = &/*tls*/ mut X; // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
+ _1 = (*_2); // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:15
+ _0 = Add(move _1, const 1_u32); // scope 1 at $DIR/simplify_locals.rs:+2:14: +2:19
+ StorageDead(_1); // scope 1 at $DIR/simplify_locals.rs:+2:18: +2:19
+ StorageDead(_2); // scope 0 at $DIR/simplify_locals.rs:+3:1: +3:2
+ return; // scope 0 at $DIR/simplify_locals.rs:+3:2: +3:2
}
}
+ // MIR for `foo` after SimplifyLocals
fn foo() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/simplify-locals-fixedpoint.rs:+0:13: +0:13
- let mut _1: (std::option::Option<u8>, std::option::Option<T>); // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:+1:30: +1:69
- let mut _2: std::option::Option<u8>; // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:+1:31: +1:49
- let mut _3: std::option::Option<T>; // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:+1:51: +1:68
- let mut _4: isize; // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:+1:22: +1:26
- let mut _5: isize; // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:+1:13: +1:20
-- let mut _7: bool; // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:+2:12: +2:20
-- let mut _8: u8; // in scope 0 at $DIR/simplify-locals-fixedpoint.rs:+2:12: +2:13
+ let mut _0: (); // return place in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+0:13: +0:13
+ let mut _1: (std::option::Option<u8>, std::option::Option<T>); // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:30: +1:69
+ let mut _2: std::option::Option<u8>; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:31: +1:49
+ let mut _3: std::option::Option<T>; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:51: +1:68
+ let mut _4: isize; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:22: +1:26
+ let mut _5: isize; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:13: +1:20
+- let mut _7: bool; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:20
+- let mut _8: u8; // in scope 0 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:13
scope 1 {
- debug a => _6; // in scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:18: +1:19
- let _6: u8; // in scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:18: +1:19
+ debug a => _6; // in scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19
+ let _6: u8; // in scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19
}
bb0: {
- StorageLive(_1); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:30: +1:69
- StorageLive(_2); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:31: +1:49
- Deinit(_2); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:31: +1:49
- discriminant(_2) = 0; // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:31: +1:49
- StorageLive(_3); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:51: +1:68
- Deinit(_3); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:51: +1:68
- discriminant(_3) = 0; // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:51: +1:68
- Deinit(_1); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:30: +1:69
- (_1.0: std::option::Option<u8>) = move _2; // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:30: +1:69
- (_1.1: std::option::Option<T>) = move _3; // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:30: +1:69
- StorageDead(_3); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:68: +1:69
- StorageDead(_2); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:68: +1:69
- _5 = discriminant((_1.0: std::option::Option<u8>)); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:12: +1:27
- switchInt(move _5) -> [1_isize: bb1, otherwise: bb3]; // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:12: +1:27
+ StorageLive(_1); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:30: +1:69
+ StorageLive(_2); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:31: +1:49
+ Deinit(_2); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:31: +1:49
+ discriminant(_2) = 0; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:31: +1:49
+ StorageLive(_3); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:51: +1:68
+ Deinit(_3); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:51: +1:68
+ discriminant(_3) = 0; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:51: +1:68
+ Deinit(_1); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:30: +1:69
+ (_1.0: std::option::Option<u8>) = move _2; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:30: +1:69
+ (_1.1: std::option::Option<T>) = move _3; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:30: +1:69
+ StorageDead(_3); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:68: +1:69
+ StorageDead(_2); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:68: +1:69
+ _5 = discriminant((_1.0: std::option::Option<u8>)); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
+ switchInt(move _5) -> [1_isize: bb1, otherwise: bb3]; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
}
bb1: {
- _4 = discriminant((_1.1: std::option::Option<T>)); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:12: +1:27
- switchInt(move _4) -> [0_isize: bb2, otherwise: bb3]; // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:12: +1:27
+ _4 = discriminant((_1.1: std::option::Option<T>)); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
+ switchInt(move _4) -> [0_isize: bb2, otherwise: bb3]; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:12: +1:27
}
bb2: {
- StorageLive(_6); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:18: +1:19
- _6 = (((_1.0: std::option::Option<u8>) as Some).0: u8); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+1:18: +1:19
-- StorageLive(_7); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+2:12: +2:20
-- StorageLive(_8); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+2:12: +2:13
-- _8 = _6; // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+2:12: +2:13
-- _7 = Gt(move _8, const 42_u8); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+2:12: +2:20
-- StorageDead(_8); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+2:19: +2:20
-- StorageDead(_7); // scope 1 at $DIR/simplify-locals-fixedpoint.rs:+4:9: +4:10
- StorageDead(_6); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:+5:5: +5:6
- goto -> bb3; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:+1:5: +5:6
+ StorageLive(_6); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19
+ _6 = (((_1.0: std::option::Option<u8>) as Some).0: u8); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+1:18: +1:19
+- StorageLive(_7); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:20
+- StorageLive(_8); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:13
+- _8 = _6; // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:13
+- _7 = Gt(move _8, const 42_u8); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:12: +2:20
+- StorageDead(_8); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+2:19: +2:20
+- StorageDead(_7); // scope 1 at $DIR/simplify_locals_fixedpoint.rs:+4:9: +4:10
+ StorageDead(_6); // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+5:5: +5:6
+ goto -> bb3; // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+1:5: +5:6
}
bb3: {
- drop(_1) -> bb4; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:+6:1: +6:2
+ drop(_1) -> bb4; // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+6:1: +6:2
}
bb4: {
- StorageDead(_1); // scope 0 at $DIR/simplify-locals-fixedpoint.rs:+6:1: +6:2
- return; // scope 0 at $DIR/simplify-locals-fixedpoint.rs:+6:2: +6:2
+ StorageDead(_1); // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+6:1: +6:2
+ return; // scope 0 at $DIR/simplify_locals_fixedpoint.rs:+6:2: +6:2
}
}
--- /dev/null
+// compile-flags: -Zmir-opt-level=1
+
+fn foo<T>() {
+ if let (Some(a), None) = (Option::<u8>::None, Option::<T>::None) {
+ if a > 42u8 {
+
+ }
+ }
+}
+
+fn main() {
+ foo::<()>();
+}
+
+// EMIT_MIR simplify_locals_fixedpoint.foo.SimplifyLocals.diff
+ // MIR for `main` after SimplifyLocals
fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+0:11: +0:11
-- let mut _1: ((), ()); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:20: +1:28
-- let mut _2: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:21: +1:23
-- let mut _3: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:25: +1:27
-- let _4: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22
-- let mut _5: ((), ()); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
-- let mut _6: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16
-- let mut _7: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20
-- let _8: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
-- let mut _9: u8; // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34
-- let mut _10: u8; // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30
-- let mut _11: Temp; // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
-+ let _1: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22
-+ let mut _2: ((), ()); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
-+ let mut _3: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16
-+ let mut _4: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20
-+ let _5: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
-+ let mut _6: u8; // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34
-+ let mut _7: u8; // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30
-+ let mut _8: Temp; // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
+ let mut _0: (); // return place in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+0:11: +0:11
+- let mut _1: ((), ()); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:20: +1:28
+- let mut _2: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:21: +1:23
+- let mut _3: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:25: +1:27
+- let _4: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
+- let mut _5: ((), ()); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
+- let mut _6: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
+- let mut _7: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
+- let _8: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
+- let mut _9: u8; // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:34
+- let mut _10: u8; // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:30
+- let mut _11: Temp; // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
++ let _1: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
++ let mut _2: ((), ()); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
++ let mut _3: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
++ let mut _4: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
++ let _5: (); // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
++ let mut _6: u8; // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:34
++ let mut _7: u8; // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:30
++ let mut _8: Temp; // in scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
scope 1 {
}
bb0: {
-- StorageLive(_1); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:20: +1:28
-- StorageLive(_2); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:21: +1:23
-- Deinit(_2); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:21: +1:23
-- StorageLive(_3); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:25: +1:27
-- Deinit(_3); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:25: +1:27
-- Deinit(_1); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:20: +1:28
-- (_1.0: ()) = move _2; // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:20: +1:28
-- (_1.1: ()) = move _3; // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:20: +1:28
-- StorageDead(_3); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:27: +1:28
-- StorageDead(_2); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:27: +1:28
-- StorageDead(_1); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:28: +1:29
-- StorageLive(_4); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22
-- StorageLive(_5); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
-- StorageLive(_6); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16
-- Deinit(_6); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16
-- StorageLive(_7); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20
-- Deinit(_7); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20
-- Deinit(_5); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
-- (_5.0: ()) = move _6; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
-- (_5.1: ()) = move _7; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
-- StorageDead(_7); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:20: +2:21
-- StorageDead(_6); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:20: +2:21
-- _4 = use_zst(move _5) -> bb1; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22
-+ StorageLive(_1); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22
-+ StorageLive(_2); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
-+ StorageLive(_3); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16
-+ Deinit(_3); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16
-+ StorageLive(_4); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20
-+ Deinit(_4); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20
-+ Deinit(_2); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
-+ (_2.0: ()) = move _3; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
-+ (_2.1: ()) = move _4; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21
-+ StorageDead(_4); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:20: +2:21
-+ StorageDead(_3); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:20: +2:21
-+ _1 = use_zst(move _2) -> bb1; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22
+- StorageLive(_1); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:20: +1:28
+- StorageLive(_2); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:21: +1:23
+- Deinit(_2); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:21: +1:23
+- StorageLive(_3); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:25: +1:27
+- Deinit(_3); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:25: +1:27
+- Deinit(_1); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:20: +1:28
+- (_1.0: ()) = move _2; // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:20: +1:28
+- (_1.1: ()) = move _3; // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:20: +1:28
+- StorageDead(_3); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:27: +1:28
+- StorageDead(_2); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:27: +1:28
+- StorageDead(_1); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+1:28: +1:29
+- StorageLive(_4); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
+- StorageLive(_5); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
+- StorageLive(_6); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
+- Deinit(_6); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
+- StorageLive(_7); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
+- Deinit(_7); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
+- Deinit(_5); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
+- (_5.0: ()) = move _6; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
+- (_5.1: ()) = move _7; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
+- StorageDead(_7); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:20: +2:21
+- StorageDead(_6); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:20: +2:21
+- _4 = use_zst(move _5) -> bb1; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
++ StorageLive(_1); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
++ StorageLive(_2); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
++ StorageLive(_3); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
++ Deinit(_3); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:14: +2:16
++ StorageLive(_4); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
++ Deinit(_4); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:18: +2:20
++ Deinit(_2); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
++ (_2.0: ()) = move _3; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
++ (_2.1: ()) = move _4; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:13: +2:21
++ StorageDead(_4); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:20: +2:21
++ StorageDead(_3); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:20: +2:21
++ _1 = use_zst(move _2) -> bb1; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:5: +2:22
// mir::Constant
- // + span: $DIR/simplify-locals-removes-unused-consts.rs:15:5: 15:12
+ // + span: $DIR/simplify_locals_removes_unused_consts.rs:15:5: 15:12
// + literal: Const { ty: fn(((), ())) {use_zst}, val: Value(<ZST>) }
}
bb1: {
-- StorageDead(_5); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:21: +2:22
-- StorageDead(_4); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:22: +2:23
-- StorageLive(_8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
-- StorageLive(_9); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34
-- StorageLive(_10); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30
-- StorageLive(_11); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
-- Deinit(_11); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
-- (_11.0: u8) = const 40_u8; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
-- _10 = (_11.0: u8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30
-- _9 = Add(move _10, const 2_u8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34
-- StorageDead(_10); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:33: +4:34
-- _8 = use_u8(move _9) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
-+ StorageDead(_2); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:21: +2:22
-+ StorageDead(_1); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:22: +2:23
-+ StorageLive(_5); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
-+ StorageLive(_6); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34
-+ StorageLive(_7); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30
-+ StorageLive(_8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
-+ Deinit(_8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
-+ (_8.0: u8) = const 40_u8; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28
-+ _7 = (_8.0: u8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30
-+ _6 = Add(move _7, const 2_u8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34
-+ StorageDead(_7); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:33: +4:34
-+ _5 = use_u8(move _6) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35
+- StorageDead(_5); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:21: +2:22
+- StorageDead(_4); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:22: +2:23
+- StorageLive(_8); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
+- StorageLive(_9); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:34
+- StorageLive(_10); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:30
+- StorageLive(_11); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
+- Deinit(_11); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
+- (_11.0: u8) = const 40_u8; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
+- _10 = (_11.0: u8); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:30
+- _9 = Add(move _10, const 2_u8); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:34
+- StorageDead(_10); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:33: +4:34
+- _8 = use_u8(move _9) -> bb2; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
++ StorageDead(_2); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:21: +2:22
++ StorageDead(_1); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+2:22: +2:23
++ StorageLive(_5); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
++ StorageLive(_6); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:34
++ StorageLive(_7); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:30
++ StorageLive(_8); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
++ Deinit(_8); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
++ (_8.0: u8) = const 40_u8; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:28
++ _7 = (_8.0: u8); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:30
++ _6 = Add(move _7, const 2_u8); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:12: +4:34
++ StorageDead(_7); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:33: +4:34
++ _5 = use_u8(move _6) -> bb2; // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:5: +4:35
// mir::Constant
- // + span: $DIR/simplify-locals-removes-unused-consts.rs:17:5: 17:11
+ // + span: $DIR/simplify_locals_removes_unused_consts.rs:17:5: 17:11
// + literal: Const { ty: fn(u8) {use_u8}, val: Value(<ZST>) }
}
bb2: {
-- StorageDead(_9); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:34: +4:35
-- StorageDead(_11); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:35: +4:36
-+ StorageDead(_6); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:34: +4:35
- StorageDead(_8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:35: +4:36
-+ StorageDead(_5); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:35: +4:36
- _0 = const (); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+0:11: +5:2
- return; // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+5:2: +5:2
+- StorageDead(_9); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:34: +4:35
+- StorageDead(_11); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:35: +4:36
++ StorageDead(_6); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:34: +4:35
+ StorageDead(_8); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:35: +4:36
++ StorageDead(_5); // scope 1 at $DIR/simplify_locals_removes_unused_consts.rs:+4:35: +4:36
+ _0 = const (); // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+0:11: +5:2
+ return; // scope 0 at $DIR/simplify_locals_removes_unused_consts.rs:+5:2: +5:2
}
}
--- /dev/null
+// unit-test: SimplifyLocals
+// compile-flags: -C overflow-checks=no
+
+fn use_zst(_: ((), ())) {}
+
+struct Temp {
+ x: u8,
+}
+
+fn use_u8(_: u8) {}
+
+// EMIT_MIR simplify_locals_removes_unused_consts.main.SimplifyLocals.diff
+fn main() {
+ let ((), ()) = ((), ());
+ use_zst(((), ()));
+
+ use_u8((Temp { x: 40 }).x + 2);
+}
+ // MIR for `map` after SimplifyLocals
fn map(_1: Option<Box<()>>) -> Option<Box<()>> {
- debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:8: +0:9
- let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+0:31: +0:46
- let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:9: +2:13
- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
-- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
-- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
-- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
+ debug x => _1; // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+0:8: +0:9
+ let mut _0: std::option::Option<std::boxed::Box<()>>; // return place in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+0:31: +0:46
+ let mut _2: isize; // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+2:9: +2:13
+ let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:14: +3:15
+ let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:25: +3:26
+- let mut _5: bool; // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+5:1: +5:2
+- let mut _6: isize; // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+5:1: +5:2
+- let mut _7: isize; // in scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+5:1: +5:2
scope 1 {
- debug x => _3; // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
+ debug x => _3; // in scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:14: +3:15
}
bb0: {
-- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
-- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
- _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
- switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:5: +1:12
+- _5 = const false; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+1:11: +1:12
+- _5 = const true; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+1:11: +1:12
+ _2 = discriminant(_1); // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+1:11: +1:12
+ switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+1:5: +1:12
}
bb1: {
- StorageLive(_3); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
- _3 = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:14: +3:15
- StorageLive(_4); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
- _4 = move _3; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:25: +3:26
- Deinit(_0); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
- ((_0 as Some).0: std::boxed::Box<()>) = move _4; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
- discriminant(_0) = 1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:20: +3:27
- StorageDead(_4); // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
- StorageDead(_3); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
- goto -> bb4; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+3:26: +3:27
+ StorageLive(_3); // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:14: +3:15
+ _3 = move ((_1 as Some).0: std::boxed::Box<()>); // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:14: +3:15
+ StorageLive(_4); // scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:25: +3:26
+ _4 = move _3; // scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:25: +3:26
+ Deinit(_0); // scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:20: +3:27
+ ((_0 as Some).0: std::boxed::Box<()>) = move _4; // scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:20: +3:27
+ discriminant(_0) = 1; // scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:20: +3:27
+ StorageDead(_4); // scope 1 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:26: +3:27
+ StorageDead(_3); // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:26: +3:27
+ goto -> bb4; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+3:26: +3:27
}
bb2: {
- unreachable; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+1:11: +1:12
+ unreachable; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+1:11: +1:12
}
bb3: {
- Deinit(_0); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21
- discriminant(_0) = 0; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21
- goto -> bb4; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+2:17: +2:21
+ Deinit(_0); // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+2:17: +2:21
+ discriminant(_0) = 0; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+2:17: +2:21
+ goto -> bb4; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+2:17: +2:21
}
bb4: {
-- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:1: +5:2
- return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:+5:2: +5:2
+- _6 = discriminant(_1); // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+5:1: +5:2
+ return; // scope 0 at $DIR/simplify_locals_removes_unused_discriminant_reads.rs:+5:2: +5:2
}
}
--- /dev/null
+// unit-test: SimplifyLocals
+
+fn map(x: Option<Box<()>>) -> Option<Box<()>> {
+ match x {
+ None => None,
+ Some(x) => Some(x),
+ }
+}
+
+fn main() {
+ map(None);
+}
+
+// EMIT_MIR simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff
+++ /dev/null
-- // MIR for `try_identity` before DestinationPropagation
-+ // MIR for `try_identity` after DestinationPropagation
-
- fn try_identity(_1: Result<u32, i32>) -> Result<u32, i32> {
- debug x => _1; // in scope 0 at $DIR/simplify_try.rs:+0:17: +0:18
- let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:+0:41: +0:57
- let _2: u32; // in scope 0 at $DIR/simplify_try.rs:+1:9: +1:10
- let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:+1:19: +1:33
- let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:+1:31: +1:32
- let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:+2:9: +2:15
- let _6: i32; // in scope 0 at $DIR/simplify_try.rs:+2:13: +2:14
- let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:+2:19: +2:51
- let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:+2:37: +2:50
- let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:+2:48: +2:49
- let _10: u32; // in scope 0 at $DIR/simplify_try.rs:+3:12: +3:13
- let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:+5:8: +5:9
- scope 1 {
-- debug y => _2; // in scope 1 at $DIR/simplify_try.rs:+1:9: +1:10
-+ debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:+1:9: +1:10
- }
- scope 2 {
- debug e => _6; // in scope 2 at $DIR/simplify_try.rs:+2:13: +2:14
- scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:22:37: 22:50
- debug t => _9; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
- }
- scope 6 (inlined from_error::<u32, i32>) { // at $DIR/simplify_try.rs:22:26: 22:51
- debug e => _8; // in scope 6 at $DIR/simplify_try.rs:12:21: 12:22
- }
- }
- scope 3 {
-- debug v => _10; // in scope 3 at $DIR/simplify_try.rs:+3:12: +3:13
-+ debug v => ((_0 as Ok).0: u32); // in scope 3 at $DIR/simplify_try.rs:+3:12: +3:13
- }
- scope 4 (inlined into_result::<u32, i32>) { // at $DIR/simplify_try.rs:21:19: 21:33
-- debug r => _4; // in scope 4 at $DIR/simplify_try.rs:8:22: 8:23
-+ debug r => _3; // in scope 4 at $DIR/simplify_try.rs:8:22: 8:23
- }
-
- bb0: {
-- StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:+1:9: +1:10
-- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:+1:19: +1:33
-- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:+1:31: +1:32
-- _4 = _1; // scope 0 at $DIR/simplify_try.rs:+1:31: +1:32
-- _3 = move _4; // scope 4 at $DIR/simplify_try.rs:9:5: 9:6
-- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:+1:32: +1:33
-+ nop; // scope 0 at $DIR/simplify_try.rs:+1:9: +1:10
-+ nop; // scope 0 at $DIR/simplify_try.rs:+1:19: +1:33
-+ nop; // scope 0 at $DIR/simplify_try.rs:+1:31: +1:32
-+ _3 = _1; // scope 0 at $DIR/simplify_try.rs:+1:31: +1:32
-+ nop; // scope 4 at $DIR/simplify_try.rs:9:5: 9:6
-+ nop; // scope 0 at $DIR/simplify_try.rs:+1:32: +1:33
- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:+1:19: +1:33
- switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:+1:13: +1:33
- }
-
- bb1: {
-- StorageLive(_10); // scope 0 at $DIR/simplify_try.rs:+3:12: +3:13
-- _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:+3:12: +3:13
-- _2 = _10; // scope 3 at $DIR/simplify_try.rs:+3:18: +3:19
-- StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:+3:18: +3:19
-- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:+4:6: +4:7
-- StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:+5:8: +5:9
-- _11 = _2; // scope 1 at $DIR/simplify_try.rs:+5:8: +5:9
-+ nop; // scope 0 at $DIR/simplify_try.rs:+3:12: +3:13
-+ ((_0 as Ok).0: u32) = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:+3:12: +3:13
-+ nop; // scope 3 at $DIR/simplify_try.rs:+3:18: +3:19
-+ nop; // scope 0 at $DIR/simplify_try.rs:+3:18: +3:19
-+ nop; // scope 0 at $DIR/simplify_try.rs:+4:6: +4:7
-+ nop; // scope 1 at $DIR/simplify_try.rs:+5:8: +5:9
-+ nop; // scope 1 at $DIR/simplify_try.rs:+5:8: +5:9
- Deinit(_0); // scope 1 at $DIR/simplify_try.rs:+5:5: +5:10
-- ((_0 as Ok).0: u32) = move _11; // scope 1 at $DIR/simplify_try.rs:+5:5: +5:10
-+ nop; // scope 1 at $DIR/simplify_try.rs:+5:5: +5:10
- discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:+5:5: +5:10
-- StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:+5:9: +5:10
-- StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:+6:1: +6:2
-+ nop; // scope 1 at $DIR/simplify_try.rs:+5:9: +5:10
-+ nop; // scope 0 at $DIR/simplify_try.rs:+6:1: +6:2
- return; // scope 0 at $DIR/simplify_try.rs:+6:2: +6:2
- }
-
- bb2: {
- unreachable; // scope 0 at $DIR/simplify_try.rs:+1:19: +1:33
- }
-
- bb3: {
- StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:+2:13: +2:14
- nop; // scope 0 at $DIR/simplify_try.rs:+2:13: +2:14
- StorageLive(_8); // scope 2 at $DIR/simplify_try.rs:+2:37: +2:50
- StorageLive(_9); // scope 2 at $DIR/simplify_try.rs:+2:48: +2:49
- nop; // scope 2 at $DIR/simplify_try.rs:+2:48: +2:49
- nop; // scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
- StorageDead(_9); // scope 2 at $DIR/simplify_try.rs:+2:49: +2:50
- nop; // scope 6 at $DIR/simplify_try.rs:13:9: 13:10
- Deinit(_0); // scope 6 at $DIR/simplify_try.rs:13:5: 13:11
- discriminant(_0) = 1; // scope 6 at $DIR/simplify_try.rs:13:5: 13:11
- StorageDead(_8); // scope 2 at $DIR/simplify_try.rs:+2:50: +2:51
- StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:+2:50: +2:51
-- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:+4:6: +4:7
-- StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:+6:1: +6:2
-+ nop; // scope 0 at $DIR/simplify_try.rs:+4:6: +4:7
-+ nop; // scope 0 at $DIR/simplify_try.rs:+6:1: +6:2
- return; // scope 0 at $DIR/simplify_try.rs:+6:2: +6:2
- }
- }
-
+++ /dev/null
-- // MIR for `try_identity` before SimplifyArmIdentity
-+ // MIR for `try_identity` after SimplifyArmIdentity
-
- fn try_identity(_1: Result<u32, i32>) -> Result<u32, i32> {
- debug x => _1; // in scope 0 at $DIR/simplify_try.rs:+0:17: +0:18
- let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:+0:41: +0:57
- let _2: u32; // in scope 0 at $DIR/simplify_try.rs:+1:9: +1:10
- let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:+1:19: +1:33
- let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:+1:31: +1:32
- let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:+2:9: +2:15
- let _6: i32; // in scope 0 at $DIR/simplify_try.rs:+2:13: +2:14
- let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:+2:19: +2:51
- let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:+2:37: +2:50
- let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:+2:48: +2:49
- let _10: u32; // in scope 0 at $DIR/simplify_try.rs:+3:12: +3:13
- let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:+5:8: +5:9
- scope 1 {
- debug y => _2; // in scope 1 at $DIR/simplify_try.rs:+1:9: +1:10
- }
- scope 2 {
- debug e => _6; // in scope 2 at $DIR/simplify_try.rs:+2:13: +2:14
- scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:22:37: 22:50
- debug t => _9; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
- }
- scope 6 (inlined from_error::<u32, i32>) { // at $DIR/simplify_try.rs:22:26: 22:51
- debug e => _8; // in scope 6 at $DIR/simplify_try.rs:12:21: 12:22
- }
- }
- scope 3 {
- debug v => _10; // in scope 3 at $DIR/simplify_try.rs:+3:12: +3:13
- }
- scope 4 (inlined into_result::<u32, i32>) { // at $DIR/simplify_try.rs:21:19: 21:33
- debug r => _4; // in scope 4 at $DIR/simplify_try.rs:8:22: 8:23
- }
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:+1:9: +1:10
- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:+1:19: +1:33
- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:+1:31: +1:32
- _4 = _1; // scope 0 at $DIR/simplify_try.rs:+1:31: +1:32
- _3 = move _4; // scope 4 at $DIR/simplify_try.rs:9:5: 9:6
- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:+1:32: +1:33
- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:+1:19: +1:33
- switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:+1:13: +1:33
- }
-
- bb1: {
- StorageLive(_10); // scope 0 at $DIR/simplify_try.rs:+3:12: +3:13
- _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:+3:12: +3:13
- _2 = _10; // scope 3 at $DIR/simplify_try.rs:+3:18: +3:19
- StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:+3:18: +3:19
- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:+4:6: +4:7
- StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:+5:8: +5:9
- _11 = _2; // scope 1 at $DIR/simplify_try.rs:+5:8: +5:9
- Deinit(_0); // scope 1 at $DIR/simplify_try.rs:+5:5: +5:10
- ((_0 as Ok).0: u32) = move _11; // scope 1 at $DIR/simplify_try.rs:+5:5: +5:10
- discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:+5:5: +5:10
- StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:+5:9: +5:10
- StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:+6:1: +6:2
- return; // scope 0 at $DIR/simplify_try.rs:+6:2: +6:2
- }
-
- bb2: {
- unreachable; // scope 0 at $DIR/simplify_try.rs:+1:19: +1:33
- }
-
- bb3: {
- StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:+2:13: +2:14
- _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify_try.rs:+2:13: +2:14
- StorageLive(_8); // scope 2 at $DIR/simplify_try.rs:+2:37: +2:50
- StorageLive(_9); // scope 2 at $DIR/simplify_try.rs:+2:48: +2:49
- _9 = _6; // scope 2 at $DIR/simplify_try.rs:+2:48: +2:49
- _8 = move _9; // scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
- StorageDead(_9); // scope 2 at $DIR/simplify_try.rs:+2:49: +2:50
- ((_0 as Err).0: i32) = move _8; // scope 6 at $DIR/simplify_try.rs:13:9: 13:10
- Deinit(_0); // scope 6 at $DIR/simplify_try.rs:13:5: 13:11
- discriminant(_0) = 1; // scope 6 at $DIR/simplify_try.rs:13:5: 13:11
- StorageDead(_8); // scope 2 at $DIR/simplify_try.rs:+2:50: +2:51
- StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:+2:50: +2:51
- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:+4:6: +4:7
- StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:+6:1: +6:2
- return; // scope 0 at $DIR/simplify_try.rs:+6:2: +6:2
- }
- }
-
+++ /dev/null
-// MIR for `try_identity` after SimplifyBranchSame
-
-fn try_identity(_1: Result<u32, i32>) -> Result<u32, i32> {
- debug x => _1; // in scope 0 at $DIR/simplify_try.rs:+0:17: +0:18
- let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:+0:41: +0:57
- let _2: u32; // in scope 0 at $DIR/simplify_try.rs:+1:9: +1:10
- let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:+1:19: +1:33
- let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:+1:31: +1:32
- let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:+2:9: +2:15
- let _6: i32; // in scope 0 at $DIR/simplify_try.rs:+2:13: +2:14
- let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:+2:19: +2:51
- let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:+2:37: +2:50
- let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:+2:48: +2:49
- let _10: u32; // in scope 0 at $DIR/simplify_try.rs:+3:12: +3:13
- let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:+5:8: +5:9
- scope 1 {
- debug y => _2; // in scope 1 at $DIR/simplify_try.rs:+1:9: +1:10
- }
- scope 2 {
- debug e => _6; // in scope 2 at $DIR/simplify_try.rs:+2:13: +2:14
- scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:22:37: 22:50
- debug t => _9; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
- }
- scope 6 (inlined from_error::<u32, i32>) { // at $DIR/simplify_try.rs:22:26: 22:51
- debug e => _8; // in scope 6 at $DIR/simplify_try.rs:12:21: 12:22
- }
- }
- scope 3 {
- debug v => _10; // in scope 3 at $DIR/simplify_try.rs:+3:12: +3:13
- }
- scope 4 (inlined into_result::<u32, i32>) { // at $DIR/simplify_try.rs:21:19: 21:33
- debug r => _4; // in scope 4 at $DIR/simplify_try.rs:8:22: 8:23
- }
-
- bb0: {
- StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:+1:9: +1:10
- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:+1:19: +1:33
- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:+1:31: +1:32
- _4 = _1; // scope 0 at $DIR/simplify_try.rs:+1:31: +1:32
- _3 = move _4; // scope 4 at $DIR/simplify_try.rs:9:5: 9:6
- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:+1:32: +1:33
- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:+1:19: +1:33
- switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:+1:13: +1:33
- }
-
- bb1: {
- StorageLive(_10); // scope 0 at $DIR/simplify_try.rs:+3:12: +3:13
- _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:+3:12: +3:13
- _2 = _10; // scope 3 at $DIR/simplify_try.rs:+3:18: +3:19
- StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:+3:18: +3:19
- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:+4:6: +4:7
- StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:+5:8: +5:9
- _11 = _2; // scope 1 at $DIR/simplify_try.rs:+5:8: +5:9
- Deinit(_0); // scope 1 at $DIR/simplify_try.rs:+5:5: +5:10
- ((_0 as Ok).0: u32) = move _11; // scope 1 at $DIR/simplify_try.rs:+5:5: +5:10
- discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:+5:5: +5:10
- StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:+5:9: +5:10
- StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:+6:1: +6:2
- return; // scope 0 at $DIR/simplify_try.rs:+6:2: +6:2
- }
-
- bb2: {
- unreachable; // scope 0 at $DIR/simplify_try.rs:+1:19: +1:33
- }
-
- bb3: {
- StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:+2:13: +2:14
- _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify_try.rs:+2:13: +2:14
- StorageLive(_8); // scope 2 at $DIR/simplify_try.rs:+2:37: +2:50
- StorageLive(_9); // scope 2 at $DIR/simplify_try.rs:+2:48: +2:49
- _9 = _6; // scope 2 at $DIR/simplify_try.rs:+2:48: +2:49
- _8 = move _9; // scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
- StorageDead(_9); // scope 2 at $DIR/simplify_try.rs:+2:49: +2:50
- ((_0 as Err).0: i32) = move _8; // scope 6 at $DIR/simplify_try.rs:13:9: 13:10
- Deinit(_0); // scope 6 at $DIR/simplify_try.rs:13:5: 13:11
- discriminant(_0) = 1; // scope 6 at $DIR/simplify_try.rs:13:5: 13:11
- StorageDead(_8); // scope 2 at $DIR/simplify_try.rs:+2:50: +2:51
- StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:+2:50: +2:51
- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:+4:6: +4:7
- StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:+6:1: +6:2
- return; // scope 0 at $DIR/simplify_try.rs:+6:2: +6:2
- }
-}
+++ /dev/null
-// MIR for `try_identity` after SimplifyLocals
-
-fn try_identity(_1: Result<u32, i32>) -> Result<u32, i32> {
- debug x => _1; // in scope 0 at $DIR/simplify_try.rs:+0:17: +0:18
- let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:+0:41: +0:57
- let mut _2: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:+1:19: +1:33
- let mut _3: isize; // in scope 0 at $DIR/simplify_try.rs:+2:9: +2:15
- let _4: i32; // in scope 0 at $DIR/simplify_try.rs:+2:13: +2:14
- let mut _5: i32; // in scope 0 at $DIR/simplify_try.rs:+2:37: +2:50
- let mut _6: i32; // in scope 0 at $DIR/simplify_try.rs:+2:48: +2:49
- scope 1 {
- debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:+1:9: +1:10
- }
- scope 2 {
- debug e => _4; // in scope 2 at $DIR/simplify_try.rs:+2:13: +2:14
- scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:22:37: 22:50
- debug t => _6; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL
- }
- scope 6 (inlined from_error::<u32, i32>) { // at $DIR/simplify_try.rs:22:26: 22:51
- debug e => _5; // in scope 6 at $DIR/simplify_try.rs:12:21: 12:22
- }
- }
- scope 3 {
- debug v => ((_0 as Ok).0: u32); // in scope 3 at $DIR/simplify_try.rs:+3:12: +3:13
- }
- scope 4 (inlined into_result::<u32, i32>) { // at $DIR/simplify_try.rs:21:19: 21:33
- debug r => _2; // in scope 4 at $DIR/simplify_try.rs:8:22: 8:23
- }
-
- bb0: {
- _2 = _1; // scope 0 at $DIR/simplify_try.rs:+1:31: +1:32
- _3 = discriminant(_2); // scope 0 at $DIR/simplify_try.rs:+1:19: +1:33
- switchInt(move _3) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:+1:13: +1:33
- }
-
- bb1: {
- ((_0 as Ok).0: u32) = ((_2 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:+3:12: +3:13
- Deinit(_0); // scope 1 at $DIR/simplify_try.rs:+5:5: +5:10
- discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:+5:5: +5:10
- return; // scope 0 at $DIR/simplify_try.rs:+6:2: +6:2
- }
-
- bb2: {
- unreachable; // scope 0 at $DIR/simplify_try.rs:+1:19: +1:33
- }
-
- bb3: {
- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:+2:13: +2:14
- StorageLive(_5); // scope 2 at $DIR/simplify_try.rs:+2:37: +2:50
- StorageLive(_6); // scope 2 at $DIR/simplify_try.rs:+2:48: +2:49
- StorageDead(_6); // scope 2 at $DIR/simplify_try.rs:+2:49: +2:50
- Deinit(_0); // scope 6 at $DIR/simplify_try.rs:13:5: 13:11
- discriminant(_0) = 1; // scope 6 at $DIR/simplify_try.rs:13:5: 13:11
- StorageDead(_5); // scope 2 at $DIR/simplify_try.rs:+2:50: +2:51
- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:+2:50: +2:51
- return; // scope 0 at $DIR/simplify_try.rs:+6:2: +6:2
- }
-}
+++ /dev/null
-// compile-flags: -Zmir-opt-level=0
-
-
-// EMIT_MIR core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir
-fn main() {
- let _fn = std::ptr::drop_in_place::<[String]> as unsafe fn(_);
-}
--- /dev/null
+// compile-flags: -Zmir-opt-level=0
+
+
+// EMIT_MIR core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir
+fn main() {
+ let _fn = std::ptr::drop_in_place::<[String]> as unsafe fn(_);
+}
+++ /dev/null
-// Test spanview block output
-// compile-flags: -Z dump-mir-spanview=block
-
-// EMIT_MIR spanview_block.main.mir_map.0.html
-fn main() {}
+++ /dev/null
-// Test spanview output (the default value for `-Z dump-mir-spanview` is "statement")
-// compile-flags: -Z dump-mir-spanview
-
-// EMIT_MIR spanview_statement.main.mir_map.0.html
-fn main() {}
+++ /dev/null
-// Test spanview terminator output
-// compile-flags: -Z dump-mir-spanview=terminator
-
-// EMIT_MIR spanview_terminator.main.mir_map.0.html
-fn main() {}
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<title>spanview_block.main.built.after</title>
+<style>
+ .line {
+ counter-increment: line;
+ }
+ .line:before {
+ content: counter(line) ": ";
+ font-family: Menlo, Monaco, monospace;
+ font-style: italic;
+ width: 3.8em;
+ display: inline-block;
+ text-align: right;
+ filter: opacity(50%);
+ -webkit-user-select: none;
+ }
+ .code {
+ color: #dddddd;
+ background-color: #222222;
+ font-family: Menlo, Monaco, monospace;
+ line-height: 1.4em;
+ border-bottom: 2px solid #222222;
+ white-space: pre;
+ display: inline-block;
+ }
+ .odd {
+ background-color: #55bbff;
+ color: #223311;
+ }
+ .even {
+ background-color: #ee7756;
+ color: #551133;
+ }
+ .code {
+ --index: calc(var(--layer) - 1);
+ padding-top: calc(var(--index) * 0.15em);
+ filter:
+ hue-rotate(calc(var(--index) * 25deg))
+ saturate(calc(100% - (var(--index) * 2%)))
+ brightness(calc(100% - (var(--index) * 1.5%)));
+ }
+ .annotation {
+ color: #4444ff;
+ font-family: monospace;
+ font-style: italic;
+ display: none;
+ -webkit-user-select: none;
+ }
+ body:active .annotation {
+ /* requires holding mouse down anywhere on the page */
+ display: inline-block;
+ }
+ span:hover .annotation {
+ /* requires hover over a span ONLY on its first line */
+ display: inline-block;
+ }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 4"><span class="line"><span class="code" style="--layer: 0">fn main() </span><span><span class="code even" style="--layer: 1" title="0: $DIR/spanview_block.rs:5:11: 5:13:
+ 5:11-5:13: Assign: _0 = const ()
+ 5:13-5:13: Return: return"><span class="annotation">0⦊</span>{}<span class="annotation">⦉0</span></span></span></span></div>
+</body>
+</html>
+++ /dev/null
-<!DOCTYPE html>
-<html>
-<head>
-<title>spanview_block.main.mir_map.0</title>
-<style>
- .line {
- counter-increment: line;
- }
- .line:before {
- content: counter(line) ": ";
- font-family: Menlo, Monaco, monospace;
- font-style: italic;
- width: 3.8em;
- display: inline-block;
- text-align: right;
- filter: opacity(50%);
- -webkit-user-select: none;
- }
- .code {
- color: #dddddd;
- background-color: #222222;
- font-family: Menlo, Monaco, monospace;
- line-height: 1.4em;
- border-bottom: 2px solid #222222;
- white-space: pre;
- display: inline-block;
- }
- .odd {
- background-color: #55bbff;
- color: #223311;
- }
- .even {
- background-color: #ee7756;
- color: #551133;
- }
- .code {
- --index: calc(var(--layer) - 1);
- padding-top: calc(var(--index) * 0.15em);
- filter:
- hue-rotate(calc(var(--index) * 25deg))
- saturate(calc(100% - (var(--index) * 2%)))
- brightness(calc(100% - (var(--index) * 1.5%)));
- }
- .annotation {
- color: #4444ff;
- font-family: monospace;
- font-style: italic;
- display: none;
- -webkit-user-select: none;
- }
- body:active .annotation {
- /* requires holding mouse down anywhere on the page */
- display: inline-block;
- }
- span:hover .annotation {
- /* requires hover over a span ONLY on its first line */
- display: inline-block;
- }
-</style>
-</head>
-<body>
-<div class="code" style="counter-reset: line 4"><span class="line"><span class="code" style="--layer: 0">fn main() </span><span><span class="code even" style="--layer: 1" title="0: $DIR/spanview-block.rs:5:11: 5:13:
- 5:11-5:13: Assign: _0 = const ()
- 5:13-5:13: Return: return"><span class="annotation">0⦊</span>{}<span class="annotation">⦉0</span></span></span></span></div>
-</body>
-</html>
--- /dev/null
+// Test spanview block output
+// compile-flags: -Z dump-mir-spanview=block
+
+// EMIT_MIR spanview_block.main.built.after.html
+fn main() {}
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<title>spanview_statement.main.built.after</title>
+<style>
+ .line {
+ counter-increment: line;
+ }
+ .line:before {
+ content: counter(line) ": ";
+ font-family: Menlo, Monaco, monospace;
+ font-style: italic;
+ width: 3.8em;
+ display: inline-block;
+ text-align: right;
+ filter: opacity(50%);
+ -webkit-user-select: none;
+ }
+ .code {
+ color: #dddddd;
+ background-color: #222222;
+ font-family: Menlo, Monaco, monospace;
+ line-height: 1.4em;
+ border-bottom: 2px solid #222222;
+ white-space: pre;
+ display: inline-block;
+ }
+ .odd {
+ background-color: #55bbff;
+ color: #223311;
+ }
+ .even {
+ background-color: #ee7756;
+ color: #551133;
+ }
+ .code {
+ --index: calc(var(--layer) - 1);
+ padding-top: calc(var(--index) * 0.15em);
+ filter:
+ hue-rotate(calc(var(--index) * 25deg))
+ saturate(calc(100% - (var(--index) * 2%)))
+ brightness(calc(100% - (var(--index) * 1.5%)));
+ }
+ .annotation {
+ color: #4444ff;
+ font-family: monospace;
+ font-style: italic;
+ display: none;
+ -webkit-user-select: none;
+ }
+ body:active .annotation {
+ /* requires holding mouse down anywhere on the page */
+ display: inline-block;
+ }
+ span:hover .annotation {
+ /* requires hover over a span ONLY on its first line */
+ display: inline-block;
+ }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 4"><span class="line"><span class="code" style="--layer: 0">fn main() </span><span><span class="code even" style="--layer: 1" title="0[0]: $DIR/spanview_statement.rs:5:11: 5:13:
+ 5:11-5:13: Assign: _0 = const ()"><span class="annotation">0[0]⦊</span>{}<span class="annotation">⦉0[0]</span></span></span><span><span class="code odd" style="--layer: 1" title="0:Return: $DIR/spanview_statement.rs:5:13: 5:13:
+ 5:13-5:13: Return: return"><span class="annotation">0:Return⦊</span>‸<span class="annotation">⦉0:Return</span></span></span></span></div>
+</body>
+</html>
+++ /dev/null
-<!DOCTYPE html>
-<html>
-<head>
-<title>spanview_statement.main.mir_map.0</title>
-<style>
- .line {
- counter-increment: line;
- }
- .line:before {
- content: counter(line) ": ";
- font-family: Menlo, Monaco, monospace;
- font-style: italic;
- width: 3.8em;
- display: inline-block;
- text-align: right;
- filter: opacity(50%);
- -webkit-user-select: none;
- }
- .code {
- color: #dddddd;
- background-color: #222222;
- font-family: Menlo, Monaco, monospace;
- line-height: 1.4em;
- border-bottom: 2px solid #222222;
- white-space: pre;
- display: inline-block;
- }
- .odd {
- background-color: #55bbff;
- color: #223311;
- }
- .even {
- background-color: #ee7756;
- color: #551133;
- }
- .code {
- --index: calc(var(--layer) - 1);
- padding-top: calc(var(--index) * 0.15em);
- filter:
- hue-rotate(calc(var(--index) * 25deg))
- saturate(calc(100% - (var(--index) * 2%)))
- brightness(calc(100% - (var(--index) * 1.5%)));
- }
- .annotation {
- color: #4444ff;
- font-family: monospace;
- font-style: italic;
- display: none;
- -webkit-user-select: none;
- }
- body:active .annotation {
- /* requires holding mouse down anywhere on the page */
- display: inline-block;
- }
- span:hover .annotation {
- /* requires hover over a span ONLY on its first line */
- display: inline-block;
- }
-</style>
-</head>
-<body>
-<div class="code" style="counter-reset: line 4"><span class="line"><span class="code" style="--layer: 0">fn main() </span><span><span class="code even" style="--layer: 1" title="0[0]: $DIR/spanview-statement.rs:5:11: 5:13:
- 5:11-5:13: Assign: _0 = const ()"><span class="annotation">0[0]⦊</span>{}<span class="annotation">⦉0[0]</span></span></span><span><span class="code odd" style="--layer: 1" title="0:Return: $DIR/spanview-statement.rs:5:13: 5:13:
- 5:13-5:13: Return: return"><span class="annotation">0:Return⦊</span>‸<span class="annotation">⦉0:Return</span></span></span></span></div>
-</body>
-</html>
--- /dev/null
+// Test spanview output (the default value for `-Z dump-mir-spanview` is "statement")
+// compile-flags: -Z dump-mir-spanview
+
+// EMIT_MIR spanview_statement.main.built.after.html
+fn main() {}
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<title>spanview_terminator.main.built.after</title>
+<style>
+ .line {
+ counter-increment: line;
+ }
+ .line:before {
+ content: counter(line) ": ";
+ font-family: Menlo, Monaco, monospace;
+ font-style: italic;
+ width: 3.8em;
+ display: inline-block;
+ text-align: right;
+ filter: opacity(50%);
+ -webkit-user-select: none;
+ }
+ .code {
+ color: #dddddd;
+ background-color: #222222;
+ font-family: Menlo, Monaco, monospace;
+ line-height: 1.4em;
+ border-bottom: 2px solid #222222;
+ white-space: pre;
+ display: inline-block;
+ }
+ .odd {
+ background-color: #55bbff;
+ color: #223311;
+ }
+ .even {
+ background-color: #ee7756;
+ color: #551133;
+ }
+ .code {
+ --index: calc(var(--layer) - 1);
+ padding-top: calc(var(--index) * 0.15em);
+ filter:
+ hue-rotate(calc(var(--index) * 25deg))
+ saturate(calc(100% - (var(--index) * 2%)))
+ brightness(calc(100% - (var(--index) * 1.5%)));
+ }
+ .annotation {
+ color: #4444ff;
+ font-family: monospace;
+ font-style: italic;
+ display: none;
+ -webkit-user-select: none;
+ }
+ body:active .annotation {
+ /* requires holding mouse down anywhere on the page */
+ display: inline-block;
+ }
+ span:hover .annotation {
+ /* requires hover over a span ONLY on its first line */
+ display: inline-block;
+ }
+</style>
+</head>
+<body>
+<div class="code" style="counter-reset: line 4"><span class="line"><span class="code" style="--layer: 0">fn main() {}</span><span><span class="code even" style="--layer: 1" title="0:Return: $DIR/spanview_terminator.rs:5:13: 5:13:
+ 5:13-5:13: Return: return"><span class="annotation">0:Return⦊</span>‸<span class="annotation">⦉0:Return</span></span></span></span></div>
+</body>
+</html>
+++ /dev/null
-<!DOCTYPE html>
-<html>
-<head>
-<title>spanview_terminator.main.mir_map.0</title>
-<style>
- .line {
- counter-increment: line;
- }
- .line:before {
- content: counter(line) ": ";
- font-family: Menlo, Monaco, monospace;
- font-style: italic;
- width: 3.8em;
- display: inline-block;
- text-align: right;
- filter: opacity(50%);
- -webkit-user-select: none;
- }
- .code {
- color: #dddddd;
- background-color: #222222;
- font-family: Menlo, Monaco, monospace;
- line-height: 1.4em;
- border-bottom: 2px solid #222222;
- white-space: pre;
- display: inline-block;
- }
- .odd {
- background-color: #55bbff;
- color: #223311;
- }
- .even {
- background-color: #ee7756;
- color: #551133;
- }
- .code {
- --index: calc(var(--layer) - 1);
- padding-top: calc(var(--index) * 0.15em);
- filter:
- hue-rotate(calc(var(--index) * 25deg))
- saturate(calc(100% - (var(--index) * 2%)))
- brightness(calc(100% - (var(--index) * 1.5%)));
- }
- .annotation {
- color: #4444ff;
- font-family: monospace;
- font-style: italic;
- display: none;
- -webkit-user-select: none;
- }
- body:active .annotation {
- /* requires holding mouse down anywhere on the page */
- display: inline-block;
- }
- span:hover .annotation {
- /* requires hover over a span ONLY on its first line */
- display: inline-block;
- }
-</style>
-</head>
-<body>
-<div class="code" style="counter-reset: line 4"><span class="line"><span class="code" style="--layer: 0">fn main() {}</span><span><span class="code even" style="--layer: 1" title="0:Return: $DIR/spanview-terminator.rs:5:13: 5:13:
- 5:13-5:13: Return: return"><span class="annotation">0:Return⦊</span>‸<span class="annotation">⦉0:Return</span></span></span></span></div>
-</body>
-</html>
--- /dev/null
+// Test spanview terminator output
+// compile-flags: -Z dump-mir-spanview=terminator
+
+// EMIT_MIR spanview_terminator.main.built.after.html
+fn main() {}
+++ /dev/null
-// MIR for `XXX` 0 mir_map
-
-static XXX: &Foo = {
- let mut _0: &Foo; // return place in scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:13: +0:25
- let _1: &Foo; // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:28: +18:2
- let _2: Foo; // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:29: +18:2
- let mut _3: &[(u32, u32)]; // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6
- let mut _4: &[(u32, u32); 42]; // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6
- let _5: &[(u32, u32); 42]; // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6
- let _6: [(u32, u32); 42]; // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:12: +17:6
- let mut _7: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:9: +3:15
- let mut _8: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:17: +3:23
- let mut _9: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:25: +3:31
- let mut _10: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:9: +4:15
- let mut _11: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:17: +4:23
- let mut _12: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:25: +4:31
- let mut _13: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:9: +5:15
- let mut _14: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:17: +5:23
- let mut _15: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:25: +5:31
- let mut _16: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:9: +6:15
- let mut _17: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:17: +6:23
- let mut _18: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:25: +6:31
- let mut _19: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:9: +7:15
- let mut _20: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:17: +7:23
- let mut _21: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:25: +7:31
- let mut _22: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:9: +8:15
- let mut _23: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:17: +8:23
- let mut _24: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:25: +8:31
- let mut _25: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:9: +9:15
- let mut _26: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:17: +9:23
- let mut _27: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:25: +9:31
- let mut _28: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:9: +10:15
- let mut _29: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:17: +10:23
- let mut _30: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:25: +10:31
- let mut _31: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:9: +11:15
- let mut _32: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:17: +11:23
- let mut _33: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:25: +11:31
- let mut _34: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:9: +12:15
- let mut _35: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:17: +12:23
- let mut _36: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:25: +12:31
- let mut _37: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:9: +13:15
- let mut _38: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:17: +13:23
- let mut _39: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:25: +13:31
- let mut _40: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:9: +14:15
- let mut _41: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:17: +14:23
- let mut _42: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:25: +14:31
- let mut _43: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:9: +15:15
- let mut _44: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:17: +15:23
- let mut _45: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:25: +15:31
- let mut _46: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:9: +16:15
- let mut _47: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:17: +16:23
- let mut _48: (u32, u32); // in scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:25: +16:31
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:28: +18:2
- StorageLive(_2); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:29: +18:2
- StorageLive(_3); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6
- StorageLive(_4); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6
- StorageLive(_5); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6
- StorageLive(_6); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:12: +17:6
- StorageLive(_7); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:9: +3:15
- _7 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:9: +3:15
- StorageLive(_8); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:17: +3:23
- _8 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:17: +3:23
- StorageLive(_9); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:25: +3:31
- _9 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+3:25: +3:31
- StorageLive(_10); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:9: +4:15
- _10 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:9: +4:15
- StorageLive(_11); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:17: +4:23
- _11 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:17: +4:23
- StorageLive(_12); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:25: +4:31
- _12 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+4:25: +4:31
- StorageLive(_13); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:9: +5:15
- _13 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:9: +5:15
- StorageLive(_14); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:17: +5:23
- _14 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:17: +5:23
- StorageLive(_15); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:25: +5:31
- _15 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+5:25: +5:31
- StorageLive(_16); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:9: +6:15
- _16 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:9: +6:15
- StorageLive(_17); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:17: +6:23
- _17 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:17: +6:23
- StorageLive(_18); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:25: +6:31
- _18 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+6:25: +6:31
- StorageLive(_19); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:9: +7:15
- _19 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:9: +7:15
- StorageLive(_20); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:17: +7:23
- _20 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:17: +7:23
- StorageLive(_21); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:25: +7:31
- _21 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+7:25: +7:31
- StorageLive(_22); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:9: +8:15
- _22 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:9: +8:15
- StorageLive(_23); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:17: +8:23
- _23 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:17: +8:23
- StorageLive(_24); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:25: +8:31
- _24 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+8:25: +8:31
- StorageLive(_25); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:9: +9:15
- _25 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:9: +9:15
- StorageLive(_26); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:17: +9:23
- _26 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:17: +9:23
- StorageLive(_27); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:25: +9:31
- _27 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+9:25: +9:31
- StorageLive(_28); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:9: +10:15
- _28 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:9: +10:15
- StorageLive(_29); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:17: +10:23
- _29 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:17: +10:23
- StorageLive(_30); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:25: +10:31
- _30 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+10:25: +10:31
- StorageLive(_31); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:9: +11:15
- _31 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:9: +11:15
- StorageLive(_32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:17: +11:23
- _32 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:17: +11:23
- StorageLive(_33); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:25: +11:31
- _33 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+11:25: +11:31
- StorageLive(_34); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:9: +12:15
- _34 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:9: +12:15
- StorageLive(_35); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:17: +12:23
- _35 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:17: +12:23
- StorageLive(_36); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:25: +12:31
- _36 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+12:25: +12:31
- StorageLive(_37); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:9: +13:15
- _37 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:9: +13:15
- StorageLive(_38); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:17: +13:23
- _38 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:17: +13:23
- StorageLive(_39); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:25: +13:31
- _39 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+13:25: +13:31
- StorageLive(_40); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:9: +14:15
- _40 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:9: +14:15
- StorageLive(_41); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:17: +14:23
- _41 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:17: +14:23
- StorageLive(_42); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:25: +14:31
- _42 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+14:25: +14:31
- StorageLive(_43); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:9: +15:15
- _43 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:9: +15:15
- StorageLive(_44); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:17: +15:23
- _44 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:17: +15:23
- StorageLive(_45); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:25: +15:31
- _45 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+15:25: +15:31
- StorageLive(_46); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:9: +16:15
- _46 = (const 0_u32, const 1_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:9: +16:15
- StorageLive(_47); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:17: +16:23
- _47 = (const 0_u32, const 2_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:17: +16:23
- StorageLive(_48); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:25: +16:31
- _48 = (const 0_u32, const 3_u32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+16:25: +16:31
- _6 = [move _7, move _8, move _9, move _10, move _11, move _12, move _13, move _14, move _15, move _16, move _17, move _18, move _19, move _20, move _21, move _22, move _23, move _24, move _25, move _26, move _27, move _28, move _29, move _30, move _31, move _32, move _33, move _34, move _35, move _36, move _37, move _38, move _39, move _40, move _41, move _42, move _43, move _44, move _45, move _46, move _47, move _48]; // scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:12: +17:6
- StorageDead(_48); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_47); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_46); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_45); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_44); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_43); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_42); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_41); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_40); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_39); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_38); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_37); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_36); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_35); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_34); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_33); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_32); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_31); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_30); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_29); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_28); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_27); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_26); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_25); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_24); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_23); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_22); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_21); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_20); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_19); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_18); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_17); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_16); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_15); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_14); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_13); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_12); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_11); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_10); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_9); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_8); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- StorageDead(_7); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- _5 = &_6; // scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6
- _4 = &(*_5); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6
- _3 = move _4 as &[(u32, u32)] (Pointer(Unsize)); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+2:11: +17:6
- StorageDead(_4); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+17:5: +17:6
- _2 = Foo { tup: const "hi", data: move _3 }; // scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:29: +18:2
- // mir::Constant
- // + span: $DIR/storage_live_dead_in_statics.rs:6:10: 6:14
- // + literal: Const { ty: &str, val: Value(Slice(..)) }
- StorageDead(_3); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+18:1: +18:2
- _1 = &_2; // scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:28: +18:2
- _0 = &(*_1); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:28: +18:2
- StorageDead(_5); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+18:1: +18:2
- StorageDead(_1); // scope 0 at $DIR/storage_live_dead_in_statics.rs:+18:1: +18:2
- return; // scope 0 at $DIR/storage_live_dead_in_statics.rs:+0:1: +18:3
- }
-}
+++ /dev/null
-// Check that when we compile the static `XXX` into MIR, we do not
-// generate `StorageStart` or `StorageEnd` statements.
-
-// EMIT_MIR storage_live_dead_in_statics.XXX.mir_map.0.mir
-static XXX: &'static Foo = &Foo {
- tup: "hi",
- data: &[
- (0, 1), (0, 2), (0, 3),
- (0, 1), (0, 2), (0, 3),
- (0, 1), (0, 2), (0, 3),
- (0, 1), (0, 2), (0, 3),
- (0, 1), (0, 2), (0, 3),
- (0, 1), (0, 2), (0, 3),
- (0, 1), (0, 2), (0, 3),
- (0, 1), (0, 2), (0, 3),
- (0, 1), (0, 2), (0, 3),
- (0, 1), (0, 2), (0, 3),
- (0, 1), (0, 2), (0, 3),
- (0, 1), (0, 2), (0, 3),
- (0, 1), (0, 2), (0, 3),
- (0, 1), (0, 2), (0, 3),
- ]
-};
-
-#[derive(Debug)]
-struct Foo {
- tup: &'static str,
- data: &'static [(u32, u32)]
-}
-
-fn main() {
- println!("{:?}", XXX);
-}
+++ /dev/null
-// EMIT_MIR tls_access.main.PreCodegen.after.mir
-// compile-flags: -Zmir-opt-level=0
-
-#![feature(thread_local)]
-
-#[thread_local]
-static mut FOO: u8 = 3;
-
-fn main() {
- unsafe {
- let a = &FOO;
- FOO = 42;
- }
-}
// MIR for `main` after PreCodegen
fn main() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/tls-access.rs:+0:11: +0:11
- let _2: *mut u8; // in scope 0 at $DIR/tls-access.rs:+2:18: +2:21
- let mut _3: *mut u8; // in scope 0 at $DIR/tls-access.rs:+3:9: +3:12
+ let mut _0: (); // return place in scope 0 at $DIR/tls_access.rs:+0:11: +0:11
+ let _2: *mut u8; // in scope 0 at $DIR/tls_access.rs:+2:18: +2:21
+ let mut _3: *mut u8; // in scope 0 at $DIR/tls_access.rs:+3:9: +3:12
scope 1 {
- let _1: &u8; // in scope 1 at $DIR/tls-access.rs:+2:13: +2:14
+ let _1: &u8; // in scope 1 at $DIR/tls_access.rs:+2:13: +2:14
scope 2 {
- debug a => _1; // in scope 2 at $DIR/tls-access.rs:+2:13: +2:14
+ debug a => _1; // in scope 2 at $DIR/tls_access.rs:+2:13: +2:14
}
}
bb0: {
- StorageLive(_1); // scope 1 at $DIR/tls-access.rs:+2:13: +2:14
- StorageLive(_2); // scope 1 at $DIR/tls-access.rs:+2:18: +2:21
- _2 = &/*tls*/ mut FOO; // scope 1 at $DIR/tls-access.rs:+2:18: +2:21
- _1 = &(*_2); // scope 1 at $DIR/tls-access.rs:+2:17: +2:21
- StorageLive(_3); // scope 2 at $DIR/tls-access.rs:+3:9: +3:12
- _3 = &/*tls*/ mut FOO; // scope 2 at $DIR/tls-access.rs:+3:9: +3:12
- (*_3) = const 42_u8; // scope 2 at $DIR/tls-access.rs:+3:9: +3:17
- StorageDead(_3); // scope 2 at $DIR/tls-access.rs:+3:17: +3:18
- _0 = const (); // scope 1 at $DIR/tls-access.rs:+1:5: +4:6
- StorageDead(_2); // scope 1 at $DIR/tls-access.rs:+4:5: +4:6
- StorageDead(_1); // scope 1 at $DIR/tls-access.rs:+4:5: +4:6
- return; // scope 0 at $DIR/tls-access.rs:+5:2: +5:2
+ StorageLive(_1); // scope 1 at $DIR/tls_access.rs:+2:13: +2:14
+ StorageLive(_2); // scope 1 at $DIR/tls_access.rs:+2:18: +2:21
+ _2 = &/*tls*/ mut FOO; // scope 1 at $DIR/tls_access.rs:+2:18: +2:21
+ _1 = &(*_2); // scope 1 at $DIR/tls_access.rs:+2:17: +2:21
+ StorageLive(_3); // scope 2 at $DIR/tls_access.rs:+3:9: +3:12
+ _3 = &/*tls*/ mut FOO; // scope 2 at $DIR/tls_access.rs:+3:9: +3:12
+ (*_3) = const 42_u8; // scope 2 at $DIR/tls_access.rs:+3:9: +3:17
+ StorageDead(_3); // scope 2 at $DIR/tls_access.rs:+3:17: +3:18
+ _0 = const (); // scope 1 at $DIR/tls_access.rs:+1:5: +4:6
+ StorageDead(_2); // scope 1 at $DIR/tls_access.rs:+4:5: +4:6
+ StorageDead(_1); // scope 1 at $DIR/tls_access.rs:+4:5: +4:6
+ return; // scope 0 at $DIR/tls_access.rs:+5:2: +5:2
}
}
--- /dev/null
+// EMIT_MIR tls_access.main.PreCodegen.after.mir
+// compile-flags: -Zmir-opt-level=0
+
+#![feature(thread_local)]
+
+#[thread_local]
+static mut FOO: u8 = 3;
+
+fn main() {
+ unsafe {
+ let a = &FOO;
+ FOO = 42;
+ }
+}
+++ /dev/null
-// MIR for `move_out_by_subslice` 0 mir_map
-
-fn move_out_by_subslice() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/uniform_array_move_out.rs:+0:27: +0:27
- let _1: [std::boxed::Box<i32>; 2]; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:9: +1:10
- let mut _2: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
- let mut _3: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
- let mut _4: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
- let mut _5: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
- let mut _6: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
- let mut _7: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
- let mut _8: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
- let mut _9: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
- let mut _10: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
- let mut _11: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
- scope 1 {
- debug a => _1; // in scope 1 at $DIR/uniform_array_move_out.rs:+1:9: +1:10
- let _12: [std::boxed::Box<i32>; 2]; // in scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:12
- scope 4 {
- debug _y => _12; // in scope 4 at $DIR/uniform_array_move_out.rs:+2:10: +2:12
- }
- }
- scope 2 {
- }
- scope 3 {
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/uniform_array_move_out.rs:+1:9: +1:10
- StorageLive(_2); // scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
- _3 = SizeOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
- _4 = AlignOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
- _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb12]; // scope 2 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
- // mir::Constant
- // + span: $DIR/uniform_array_move_out.rs:11:14: 11:19
- // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
- }
-
- bb1: {
- StorageLive(_6); // scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
- _6 = ShallowInitBox(move _5, i32); // scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
- (*_6) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:+1:18: +1:19
- _2 = move _6; // scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
- drop(_6) -> [return: bb2, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:18: +1:19
- }
-
- bb2: {
- StorageDead(_6); // scope 0 at $DIR/uniform_array_move_out.rs:+1:18: +1:19
- StorageLive(_7); // scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
- _8 = SizeOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
- _9 = AlignOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
- _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb11]; // scope 3 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
- // mir::Constant
- // + span: $DIR/uniform_array_move_out.rs:11:21: 11:26
- // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
- }
-
- bb3: {
- StorageLive(_11); // scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
- _11 = ShallowInitBox(move _10, i32); // scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
- (*_11) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:+1:25: +1:26
- _7 = move _11; // scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
- drop(_11) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:25: +1:26
- }
-
- bb4: {
- StorageDead(_11); // scope 0 at $DIR/uniform_array_move_out.rs:+1:25: +1:26
- _1 = [move _2, move _7]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:13: +1:27
- drop(_7) -> [return: bb5, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
- }
-
- bb5: {
- StorageDead(_7); // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
- drop(_2) -> [return: bb6, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
- }
-
- bb6: {
- StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
- FakeRead(ForLet(None), _1); // scope 0 at $DIR/uniform_array_move_out.rs:+1:9: +1:10
- StorageLive(_12); // scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:12
- _12 = move _1[0..2]; // scope 1 at $DIR/uniform_array_move_out.rs:+2:10: +2:12
- _0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:+0:27: +3:2
- drop(_12) -> [return: bb7, unwind: bb9]; // scope 1 at $DIR/uniform_array_move_out.rs:+3:1: +3:2
- }
-
- bb7: {
- StorageDead(_12); // scope 1 at $DIR/uniform_array_move_out.rs:+3:1: +3:2
- drop(_1) -> [return: bb8, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:+3:1: +3:2
- }
-
- bb8: {
- StorageDead(_1); // scope 0 at $DIR/uniform_array_move_out.rs:+3:1: +3:2
- return; // scope 0 at $DIR/uniform_array_move_out.rs:+3:2: +3:2
- }
-
- bb9 (cleanup): {
- drop(_1) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:+3:1: +3:2
- }
-
- bb10 (cleanup): {
- drop(_7) -> bb11; // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
- }
-
- bb11 (cleanup): {
- drop(_2) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
- }
-
- bb12 (cleanup): {
- resume; // scope 0 at $DIR/uniform_array_move_out.rs:+0:1: +3:2
- }
-}
+++ /dev/null
-// MIR for `move_out_from_end` 0 mir_map
-
-fn move_out_from_end() -> () {
- let mut _0: (); // return place in scope 0 at $DIR/uniform_array_move_out.rs:+0:24: +0:24
- let _1: [std::boxed::Box<i32>; 2]; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:9: +1:10
- let mut _2: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
- let mut _3: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
- let mut _4: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
- let mut _5: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
- let mut _6: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
- let mut _7: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
- let mut _8: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
- let mut _9: usize; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
- let mut _10: *mut u8; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
- let mut _11: std::boxed::Box<i32>; // in scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
- scope 1 {
- debug a => _1; // in scope 1 at $DIR/uniform_array_move_out.rs:+1:9: +1:10
- let _12: std::boxed::Box<i32>; // in scope 1 at $DIR/uniform_array_move_out.rs:+2:14: +2:16
- scope 4 {
- debug _y => _12; // in scope 4 at $DIR/uniform_array_move_out.rs:+2:14: +2:16
- }
- }
- scope 2 {
- }
- scope 3 {
- }
-
- bb0: {
- StorageLive(_1); // scope 0 at $DIR/uniform_array_move_out.rs:+1:9: +1:10
- StorageLive(_2); // scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
- _3 = SizeOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
- _4 = AlignOf(i32); // scope 2 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
- _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb12]; // scope 2 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
- // mir::Constant
- // + span: $DIR/uniform_array_move_out.rs:5:14: 5:19
- // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
- }
-
- bb1: {
- StorageLive(_6); // scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
- _6 = ShallowInitBox(move _5, i32); // scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
- (*_6) = const 1_i32; // scope 0 at $DIR/uniform_array_move_out.rs:+1:18: +1:19
- _2 = move _6; // scope 0 at $DIR/uniform_array_move_out.rs:+1:14: +1:19
- drop(_6) -> [return: bb2, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:18: +1:19
- }
-
- bb2: {
- StorageDead(_6); // scope 0 at $DIR/uniform_array_move_out.rs:+1:18: +1:19
- StorageLive(_7); // scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
- _8 = SizeOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
- _9 = AlignOf(i32); // scope 3 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
- _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb11]; // scope 3 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
- // mir::Constant
- // + span: $DIR/uniform_array_move_out.rs:5:21: 5:26
- // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) }
- }
-
- bb3: {
- StorageLive(_11); // scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
- _11 = ShallowInitBox(move _10, i32); // scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
- (*_11) = const 2_i32; // scope 0 at $DIR/uniform_array_move_out.rs:+1:25: +1:26
- _7 = move _11; // scope 0 at $DIR/uniform_array_move_out.rs:+1:21: +1:26
- drop(_11) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:25: +1:26
- }
-
- bb4: {
- StorageDead(_11); // scope 0 at $DIR/uniform_array_move_out.rs:+1:25: +1:26
- _1 = [move _2, move _7]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:13: +1:27
- drop(_7) -> [return: bb5, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
- }
-
- bb5: {
- StorageDead(_7); // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
- drop(_2) -> [return: bb6, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
- }
-
- bb6: {
- StorageDead(_2); // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
- FakeRead(ForLet(None), _1); // scope 0 at $DIR/uniform_array_move_out.rs:+1:9: +1:10
- StorageLive(_12); // scope 1 at $DIR/uniform_array_move_out.rs:+2:14: +2:16
- _12 = move _1[1 of 2]; // scope 1 at $DIR/uniform_array_move_out.rs:+2:14: +2:16
- _0 = const (); // scope 0 at $DIR/uniform_array_move_out.rs:+0:24: +3:2
- drop(_12) -> [return: bb7, unwind: bb9]; // scope 1 at $DIR/uniform_array_move_out.rs:+3:1: +3:2
- }
-
- bb7: {
- StorageDead(_12); // scope 1 at $DIR/uniform_array_move_out.rs:+3:1: +3:2
- drop(_1) -> [return: bb8, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:+3:1: +3:2
- }
-
- bb8: {
- StorageDead(_1); // scope 0 at $DIR/uniform_array_move_out.rs:+3:1: +3:2
- return; // scope 0 at $DIR/uniform_array_move_out.rs:+3:2: +3:2
- }
-
- bb9 (cleanup): {
- drop(_1) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:+3:1: +3:2
- }
-
- bb10 (cleanup): {
- drop(_7) -> bb11; // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
- }
-
- bb11 (cleanup): {
- drop(_2) -> bb12; // scope 0 at $DIR/uniform_array_move_out.rs:+1:26: +1:27
- }
-
- bb12 (cleanup): {
- resume; // scope 0 at $DIR/uniform_array_move_out.rs:+0:1: +3:2
- }
-}
+++ /dev/null
-#![feature(box_syntax)]
-
-// EMIT_MIR uniform_array_move_out.move_out_from_end.mir_map.0.mir
-fn move_out_from_end() {
- let a = [box 1, box 2];
- let [.., _y] = a;
-}
-
-// EMIT_MIR uniform_array_move_out.move_out_by_subslice.mir_map.0.mir
-fn move_out_by_subslice() {
- let a = [box 1, box 2];
- let [_y @ ..] = a;
-}
-
-fn main() {
- move_out_by_subslice();
- move_out_from_end();
-}
+++ /dev/null
-#![feature(never_type)]
-
-pub enum Void {}
-
-// EMIT_MIR uninhabited_enum.process_never.SimplifyLocals.after.mir
-#[no_mangle]
-pub fn process_never(input: *const !) {
- let _input = unsafe { &*input };
-}
-
-// EMIT_MIR uninhabited_enum.process_void.SimplifyLocals.after.mir
-#[no_mangle]
-pub fn process_void(input: *const Void) {
- let _input = unsafe { &*input };
- // In the future, this should end with `unreachable`, but we currently only do
- // unreachability analysis for `!`.
-}
-
-fn main() {}
// MIR for `process_never` after SimplifyLocals
fn process_never(_1: *const !) -> () {
- debug input => _1; // in scope 0 at $DIR/uninhabited-enum.rs:+0:22: +0:27
- let mut _0: (); // return place in scope 0 at $DIR/uninhabited-enum.rs:+0:39: +0:39
- let _2: &!; // in scope 0 at $DIR/uninhabited-enum.rs:+1:8: +1:14
+ debug input => _1; // in scope 0 at $DIR/uninhabited_enum.rs:+0:22: +0:27
+ let mut _0: (); // return place in scope 0 at $DIR/uninhabited_enum.rs:+0:39: +0:39
+ let _2: &!; // in scope 0 at $DIR/uninhabited_enum.rs:+1:8: +1:14
scope 1 {
- debug _input => _2; // in scope 1 at $DIR/uninhabited-enum.rs:+1:8: +1:14
+ debug _input => _2; // in scope 1 at $DIR/uninhabited_enum.rs:+1:8: +1:14
}
scope 2 {
}
bb0: {
- unreachable; // scope 0 at $DIR/uninhabited-enum.rs:+0:39: +2:2
+ unreachable; // scope 0 at $DIR/uninhabited_enum.rs:+0:39: +2:2
}
}
// MIR for `process_void` after SimplifyLocals
fn process_void(_1: *const Void) -> () {
- debug input => _1; // in scope 0 at $DIR/uninhabited-enum.rs:+0:21: +0:26
- let mut _0: (); // return place in scope 0 at $DIR/uninhabited-enum.rs:+0:41: +0:41
- let _2: &Void; // in scope 0 at $DIR/uninhabited-enum.rs:+1:8: +1:14
+ debug input => _1; // in scope 0 at $DIR/uninhabited_enum.rs:+0:21: +0:26
+ let mut _0: (); // return place in scope 0 at $DIR/uninhabited_enum.rs:+0:41: +0:41
+ let _2: &Void; // in scope 0 at $DIR/uninhabited_enum.rs:+1:8: +1:14
scope 1 {
- debug _input => _2; // in scope 1 at $DIR/uninhabited-enum.rs:+1:8: +1:14
+ debug _input => _2; // in scope 1 at $DIR/uninhabited_enum.rs:+1:8: +1:14
}
scope 2 {
}
bb0: {
- StorageLive(_2); // scope 0 at $DIR/uninhabited-enum.rs:+1:8: +1:14
- StorageDead(_2); // scope 0 at $DIR/uninhabited-enum.rs:+4:1: +4:2
- return; // scope 0 at $DIR/uninhabited-enum.rs:+4:2: +4:2
+ StorageLive(_2); // scope 0 at $DIR/uninhabited_enum.rs:+1:8: +1:14
+ StorageDead(_2); // scope 0 at $DIR/uninhabited_enum.rs:+4:1: +4:2
+ return; // scope 0 at $DIR/uninhabited_enum.rs:+4:2: +4:2
}
}
--- /dev/null
+#![feature(never_type)]
+
+pub enum Void {}
+
+// EMIT_MIR uninhabited_enum.process_never.SimplifyLocals.after.mir
+#[no_mangle]
+pub fn process_never(input: *const !) {
+ let _input = unsafe { &*input };
+}
+
+// EMIT_MIR uninhabited_enum.process_void.SimplifyLocals.after.mir
+#[no_mangle]
+pub fn process_void(input: *const Void) {
+ let _input = unsafe { &*input };
+ // In the future, this should end with `unreachable`, but we currently only do
+ // unreachability analysis for `!`.
+}
+
+fn main() {}
+++ /dev/null
-// Test that we don't ICE when trying to dump MIR for unusual item types and
-// that we don't create filenames containing `<` and `>`
-// compile-flags: -Zmir-opt-level=0
-
-
-struct A;
-
-// EMIT_MIR unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.mir
-impl A {
- const ASSOCIATED_CONSTANT: i32 = 2;
-}
-
-// See #59021
-// EMIT_MIR unusual_item_types.Test-X-{constructor#0}.mir_map.0.mir
-enum Test {
- X(usize),
- Y { a: usize },
-}
-
-// EMIT_MIR unusual_item_types.E-V-{constant#0}.mir_map.0.mir
-enum E {
- V = 5,
-}
-
-fn main() {
- let f = Test::X as fn(usize) -> Test;
-// EMIT_MIR core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir
- let v = Vec::<i32>::new();
-}
--- /dev/null
+// MIR for `E::V::{constant#0}` after built
+
+E::V::{constant#0}: isize = {
+ let mut _0: isize; // return place in scope 0 at $DIR/unusual_item_types.rs:+0:9: +0:10
+
+ bb0: {
+ _0 = const 5_isize; // scope 0 at $DIR/unusual_item_types.rs:+0:9: +0:10
+ return; // scope 0 at $DIR/unusual_item_types.rs:+0:9: +0:10
+ }
+}
+++ /dev/null
-// MIR for `E::V::{constant#0}` 0 mir_map
-
-E::V::{constant#0}: isize = {
- let mut _0: isize; // return place in scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10
-
- bb0: {
- _0 = const 5_isize; // scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10
- return; // scope 0 at $DIR/unusual-item-types.rs:+0:9: +0:10
- }
-}
--- /dev/null
+// MIR for `Test::X` after built
+
+fn Test::X(_1: usize) -> Test {
+ let mut _0: Test; // return place in scope 0 at $DIR/unusual_item_types.rs:+0:5: +0:6
+
+ bb0: {
+ Deinit(_0); // scope 0 at $DIR/unusual_item_types.rs:+0:5: +0:6
+ ((_0 as X).0: usize) = move _1; // scope 0 at $DIR/unusual_item_types.rs:+0:5: +0:6
+ discriminant(_0) = 0; // scope 0 at $DIR/unusual_item_types.rs:+0:5: +0:6
+ return; // scope 0 at $DIR/unusual_item_types.rs:+0:5: +0:6
+ }
+}
+++ /dev/null
-// MIR for `Test::X` 0 mir_map
-
-fn Test::X(_1: usize) -> Test {
- let mut _0: Test; // return place in scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
-
- bb0: {
- Deinit(_0); // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
- ((_0 as X).0: usize) = move _1; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
- discriminant(_0) = 0; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
- return; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:6
- }
-}
--- /dev/null
+// Test that we don't ICE when trying to dump MIR for unusual item types and
+// that we don't create filenames containing `<` and `>`
+// compile-flags: -Zmir-opt-level=0
+
+
+struct A;
+
+// EMIT_MIR unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.built.after.mir
+impl A {
+ const ASSOCIATED_CONSTANT: i32 = 2;
+}
+
+// See #59021
+// EMIT_MIR unusual_item_types.Test-X-{constructor#0}.built.after.mir
+enum Test {
+ X(usize),
+ Y { a: usize },
+}
+
+// EMIT_MIR unusual_item_types.E-V-{constant#0}.built.after.mir
+enum E {
+ V = 5,
+}
+
+fn main() {
+ let f = Test::X as fn(usize) -> Test;
+// EMIT_MIR core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir
+ let v = Vec::<i32>::new();
+}
--- /dev/null
+// MIR for `<impl at $DIR/unusual_item_types.rs:9:1: 9:7>::ASSOCIATED_CONSTANT` after built
+
+const <impl at $DIR/unusual_item_types.rs:9:1: 9:7>::ASSOCIATED_CONSTANT: i32 = {
+ let mut _0: i32; // return place in scope 0 at $DIR/unusual_item_types.rs:+0:32: +0:35
+
+ bb0: {
+ _0 = const 2_i32; // scope 0 at $DIR/unusual_item_types.rs:+0:38: +0:39
+ return; // scope 0 at $DIR/unusual_item_types.rs:+0:5: +0:40
+ }
+}
+++ /dev/null
-// MIR for `<impl at $DIR/unusual-item-types.rs:9:1: 9:7>::ASSOCIATED_CONSTANT` 0 mir_map
-
-const <impl at $DIR/unusual-item-types.rs:9:1: 9:7>::ASSOCIATED_CONSTANT: i32 = {
- let mut _0: i32; // return place in scope 0 at $DIR/unusual-item-types.rs:+0:32: +0:35
-
- bb0: {
- _0 = const 2_i32; // scope 0 at $DIR/unusual-item-types.rs:+0:38: +0:39
- return; // scope 0 at $DIR/unusual-item-types.rs:+0:5: +0:40
- }
-}
+++ /dev/null
-// Test that we correctly generate StorageDead statements for while loop
-// conditions on all branches
-
-fn get_bool(c: bool) -> bool {
- c
-}
-
-// EMIT_MIR while_storage.while_loop.PreCodegen.after.mir
-fn while_loop(c: bool) {
- while get_bool(c) {
- if get_bool(c) {
- break;
- }
- }
-}
-
-fn main() {
- while_loop(false);
-}
--- /dev/null
+// Test that we correctly generate StorageDead statements for while loop
+// conditions on all branches
+
+fn get_bool(c: bool) -> bool {
+ c
+}
+
+// EMIT_MIR while_storage.while_loop.PreCodegen.after.mir
+fn while_loop(c: bool) {
+ while get_bool(c) {
+ if get_bool(c) {
+ break;
+ }
+ }
+}
+
+fn main() {
+ while_loop(false);
+}
// MIR for `while_loop` after PreCodegen
fn while_loop(_1: bool) -> () {
- debug c => _1; // in scope 0 at $DIR/while-storage.rs:+0:15: +0:16
- let mut _0: (); // return place in scope 0 at $DIR/while-storage.rs:+0:24: +0:24
- let mut _2: bool; // in scope 0 at $DIR/while-storage.rs:+1:11: +1:22
- let mut _3: bool; // in scope 0 at $DIR/while-storage.rs:+1:20: +1:21
- let mut _4: bool; // in scope 0 at $DIR/while-storage.rs:+2:12: +2:23
- let mut _5: bool; // in scope 0 at $DIR/while-storage.rs:+2:21: +2:22
+ debug c => _1; // in scope 0 at $DIR/while_storage.rs:+0:15: +0:16
+ let mut _0: (); // return place in scope 0 at $DIR/while_storage.rs:+0:24: +0:24
+ let mut _2: bool; // in scope 0 at $DIR/while_storage.rs:+1:11: +1:22
+ let mut _3: bool; // in scope 0 at $DIR/while_storage.rs:+1:20: +1:21
+ let mut _4: bool; // in scope 0 at $DIR/while_storage.rs:+2:12: +2:23
+ let mut _5: bool; // in scope 0 at $DIR/while_storage.rs:+2:21: +2:22
bb0: {
- goto -> bb1; // scope 0 at $DIR/while-storage.rs:+1:5: +5:6
+ goto -> bb1; // scope 0 at $DIR/while_storage.rs:+1:5: +5:6
}
bb1: {
- StorageLive(_2); // scope 0 at $DIR/while-storage.rs:+1:11: +1:22
- StorageLive(_3); // scope 0 at $DIR/while-storage.rs:+1:20: +1:21
- _3 = _1; // scope 0 at $DIR/while-storage.rs:+1:20: +1:21
- _2 = get_bool(move _3) -> bb2; // scope 0 at $DIR/while-storage.rs:+1:11: +1:22
+ StorageLive(_2); // scope 0 at $DIR/while_storage.rs:+1:11: +1:22
+ StorageLive(_3); // scope 0 at $DIR/while_storage.rs:+1:20: +1:21
+ _3 = _1; // scope 0 at $DIR/while_storage.rs:+1:20: +1:21
+ _2 = get_bool(move _3) -> bb2; // scope 0 at $DIR/while_storage.rs:+1:11: +1:22
// mir::Constant
- // + span: $DIR/while-storage.rs:10:11: 10:19
+ // + span: $DIR/while_storage.rs:10:11: 10:19
// + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value(<ZST>) }
}
bb2: {
- StorageDead(_3); // scope 0 at $DIR/while-storage.rs:+1:21: +1:22
- switchInt(move _2) -> [false: bb7, otherwise: bb3]; // scope 0 at $DIR/while-storage.rs:+1:11: +1:22
+ StorageDead(_3); // scope 0 at $DIR/while_storage.rs:+1:21: +1:22
+ switchInt(move _2) -> [false: bb7, otherwise: bb3]; // scope 0 at $DIR/while_storage.rs:+1:11: +1:22
}
bb3: {
- StorageLive(_4); // scope 0 at $DIR/while-storage.rs:+2:12: +2:23
- StorageLive(_5); // scope 0 at $DIR/while-storage.rs:+2:21: +2:22
- _5 = _1; // scope 0 at $DIR/while-storage.rs:+2:21: +2:22
- _4 = get_bool(move _5) -> bb4; // scope 0 at $DIR/while-storage.rs:+2:12: +2:23
+ StorageLive(_4); // scope 0 at $DIR/while_storage.rs:+2:12: +2:23
+ StorageLive(_5); // scope 0 at $DIR/while_storage.rs:+2:21: +2:22
+ _5 = _1; // scope 0 at $DIR/while_storage.rs:+2:21: +2:22
+ _4 = get_bool(move _5) -> bb4; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23
// mir::Constant
- // + span: $DIR/while-storage.rs:11:12: 11:20
+ // + span: $DIR/while_storage.rs:11:12: 11:20
// + literal: Const { ty: fn(bool) -> bool {get_bool}, val: Value(<ZST>) }
}
bb4: {
- StorageDead(_5); // scope 0 at $DIR/while-storage.rs:+2:22: +2:23
- switchInt(move _4) -> [false: bb6, otherwise: bb5]; // scope 0 at $DIR/while-storage.rs:+2:12: +2:23
+ StorageDead(_5); // scope 0 at $DIR/while_storage.rs:+2:22: +2:23
+ switchInt(move _4) -> [false: bb6, otherwise: bb5]; // scope 0 at $DIR/while_storage.rs:+2:12: +2:23
}
bb5: {
- StorageDead(_4); // scope 0 at $DIR/while-storage.rs:+4:9: +4:10
+ StorageDead(_4); // scope 0 at $DIR/while_storage.rs:+4:9: +4:10
goto -> bb8; // scope 0 at no-location
}
bb6: {
- StorageDead(_4); // scope 0 at $DIR/while-storage.rs:+4:9: +4:10
- StorageDead(_2); // scope 0 at $DIR/while-storage.rs:+5:5: +5:6
- goto -> bb1; // scope 0 at $DIR/while-storage.rs:+1:5: +5:6
+ StorageDead(_4); // scope 0 at $DIR/while_storage.rs:+4:9: +4:10
+ StorageDead(_2); // scope 0 at $DIR/while_storage.rs:+5:5: +5:6
+ goto -> bb1; // scope 0 at $DIR/while_storage.rs:+1:5: +5:6
}
bb7: {
}
bb8: {
- StorageDead(_2); // scope 0 at $DIR/while-storage.rs:+5:5: +5:6
- return; // scope 0 at $DIR/while-storage.rs:+6:2: +6:2
+ StorageDead(_2); // scope 0 at $DIR/while_storage.rs:+5:5: +5:6
+ return; // scope 0 at $DIR/while_storage.rs:+6:2: +6:2
}
}
--- /dev/null
+# ignore-i686-pc-windows-gnu
+
+# This test doesn't work on 32-bit MinGW as cdylib has its own copy of unwinder
+# so cross-DLL unwinding does not work.
+
+include ../tools.mk
+
+all:
+ $(RUSTC) bar.rs --crate-type=cdylib
+ $(RUSTC) foo.rs
+ $(call RUN,foo) 2>&1 | $(CGREP) "Rust cannot catch foreign exceptions"
--- /dev/null
+#![crate_type = "cdylib"]
+#![feature(c_unwind)]
+
+#[no_mangle]
+extern "C-unwind" fn panic() {
+ panic!();
+}
--- /dev/null
+#![feature(c_unwind)]
+
+#[cfg_attr(not(windows), link(name = "bar"))]
+#[cfg_attr(windows, link(name = "bar.dll"))]
+extern "C-unwind" {
+ fn panic();
+}
+
+fn main() {
+ let _ = std::panic::catch_unwind(|| {
+ unsafe { panic() };
+ });
+}
$(RUSTC) --emit=obj app.rs
nm $(TMPDIR)/app.o | $(CGREP) rust_begin_unwind
nm $(TMPDIR)/app.o | $(CGREP) rust_eh_personality
- nm $(TMPDIR)/app.o | $(CGREP) rust_oom
+ nm $(TMPDIR)/app.o | $(CGREP) __rg_oom
#![crate_type = "bin"]
-#![feature(lang_items)]
+#![feature(lang_items, alloc_error_handler)]
#![no_main]
#![no_std]
#[lang = "eh_personality"]
fn eh() {}
-#[lang = "oom"]
+#[alloc_error_handler]
fn oom(_: Layout) -> ! {
loop {}
}
{ "type": "test", "event": "started", "name": "a" }
{ "type": "test", "name": "a", "event": "ok" }
{ "type": "test", "event": "started", "name": "b" }
-{ "type": "test", "name": "b", "event": "failed", "stdout": "thread 'main' panicked at 'assertion failed: false', f.rs:9:5\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace\n" }
+{ "type": "test", "name": "b", "event": "failed", "stdout": "thread 'b' panicked at 'assertion failed: false', f.rs:9:5\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace\n" }
{ "type": "test", "event": "started", "name": "c" }
{ "type": "test", "name": "c", "event": "ok" }
{ "type": "test", "event": "started", "name": "d" }
{ "type": "test", "event": "started", "name": "a" }
{ "type": "test", "name": "a", "event": "ok", "stdout": "print from successful test\n" }
{ "type": "test", "event": "started", "name": "b" }
-{ "type": "test", "name": "b", "event": "failed", "stdout": "thread 'main' panicked at 'assertion failed: false', f.rs:9:5\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace\n" }
+{ "type": "test", "name": "b", "event": "failed", "stdout": "thread 'b' panicked at 'assertion failed: false', f.rs:9:5\nnote: run with `RUST_BACKTRACE=1` environment variable to display a backtrace\n" }
{ "type": "test", "event": "started", "name": "c" }
-{ "type": "test", "name": "c", "event": "ok", "stdout": "thread 'main' panicked at 'assertion failed: false', f.rs:15:5\n" }
+{ "type": "test", "name": "c", "event": "ok", "stdout": "thread 'c' panicked at 'assertion failed: false', f.rs:15:5\n" }
{ "type": "test", "event": "started", "name": "d" }
{ "type": "test", "name": "d", "event": "ignored", "message": "msg" }
{ "type": "suite", "event": "failed", "passed": 2, "failed": 1, "ignored": 1, "measured": 0, "filtered_out": 0, "exec_time": $TIME }
let crate_items = tcx.hir_crate_items(());
for id in crate_items.items() {
- if matches!(tcx.def_kind(id.def_id), DefKind::Fn) {
- bodies.push(id.def_id);
+ if matches!(tcx.def_kind(id.owner_id), DefKind::Fn) {
+ bodies.push(id.owner_id);
}
}
for id in crate_items.trait_items() {
- if matches!(tcx.def_kind(id.def_id), DefKind::AssocFn) {
+ if matches!(tcx.def_kind(id.owner_id), DefKind::AssocFn) {
let trait_item = hir.trait_item(id);
if let rustc_hir::TraitItemKind::Fn(_, trait_fn) = &trait_item.kind {
if let rustc_hir::TraitFn::Provided(_) = trait_fn {
- bodies.push(trait_item.def_id);
+ bodies.push(trait_item.owner_id);
}
}
}
}
for id in crate_items.impl_items() {
- if matches!(tcx.def_kind(id.def_id), DefKind::AssocFn) {
- bodies.push(id.def_id);
+ if matches!(tcx.def_kind(id.owner_id), DefKind::AssocFn) {
+ bodies.push(id.owner_id);
}
}
toolchain-only:
$(RUSTDOC) -Z unstable-options --emit=toolchain-shared-resources --output $(TOOLCHAIN_ONLY) --resource-suffix=-xxx --extend-css z.css x.rs
- [ -e $(TOOLCHAIN_ONLY)/storage-xxx.js ]
- ! [ -e $(TOOLCHAIN_ONLY)/SourceSerif4-It.ttf.woff2 ]
+ [ -e $(TOOLCHAIN_ONLY)/static.files/storage-*.js ]
+ [ -e $(TOOLCHAIN_ONLY)/static.files/SourceSerif4-It-*.ttf.woff2 ]
! [ -e $(TOOLCHAIN_ONLY)/search-index-xxx.js ]
! [ -e $(TOOLCHAIN_ONLY)/x/index.html ]
! [ -e $(TOOLCHAIN_ONLY)/theme.css ]
- [ -e $(TOOLCHAIN_ONLY)/main-xxx.js ]
+ [ -e $(TOOLCHAIN_ONLY)/static.files/main-*.js ]
! [ -e $(TOOLCHAIN_ONLY)/y-xxx.css ]
all-shared:
$(RUSTDOC) -Z unstable-options --emit=toolchain-shared-resources,unversioned-shared-resources --output $(ALL_SHARED) --resource-suffix=-xxx --extend-css z.css x.rs
- [ -e $(ALL_SHARED)/storage-xxx.js ]
- [ -e $(ALL_SHARED)/SourceSerif4-It.ttf.woff2 ]
+ [ -e $(ALL_SHARED)/static.files/storage-*.js ]
+ [ -e $(ALL_SHARED)/static.files/SourceSerif4-It-*.ttf.woff2 ]
! [ -e $(ALL_SHARED)/search-index-xxx.js ]
! [ -e $(ALL_SHARED)/settings.html ]
! [ -e $(ALL_SHARED)/x ]
! [ -e $(ALL_SHARED)/src ]
! [ -e $(ALL_SHARED)/theme.css ]
- [ -e $(ALL_SHARED)/main-xxx.js ]
+ [ -e $(ALL_SHARED)/static.files/main-*.js ]
! [ -e $(ALL_SHARED)/y-xxx.css ]
Provide width of the output for truncated error
messages
--json CONFIG Configure the structure of JSON diagnostics
- --disable-minification
- Disable minification applied on JS files
-A, --allow LINT Set lint allowed
-W, --warn LINT Set lint warnings
--force-warn LINT
--scrape-tests Include test code when scraping examples
--with-examples path to function call information (for displaying examples in the documentation)
+ --disable-minification
+ removed
--plugin-path DIR
removed, see issue #44136
<https://github.com/rust-lang/rust/issues/44136> for
--- /dev/null
+include ../../run-make-fulldeps/tools.mk
+
+# ignore-cross-compile
+
+all:
+ # Smoke-test that `#[bench]` isn't entirely broken.
+ $(RUSTC) --test smokebench.rs -O
+ $(call RUN,smokebench --bench)
+ $(call RUN,smokebench --bench noiter)
+ $(call RUN,smokebench --bench yesiter)
+ $(call RUN,smokebench)
--- /dev/null
+#![feature(test)]
+extern crate test;
+
+#[bench]
+fn smoke_yesiter(b: &mut test::Bencher) {
+ let mut i = 0usize;
+ b.iter(|| {
+ i = i.wrapping_add(1);
+ i
+ })
+}
+
+#[bench]
+fn smoke_noiter(_: &mut test::Bencher) {}
--- /dev/null
+include ../../run-make-fulldeps/tools.mk
+
+all:
+ $(RUSTC) --print uwu 2>&1 | diff - valid-print-requests.stderr
--- /dev/null
+error: unknown print request `uwu`. Valid print requests are: `crate-name`, `file-names`, `sysroot`, `target-libdir`, `cfg`, `calling-conventions`, `target-list`, `target-cpus`, `target-features`, `relocation-models`, `code-models`, `tls-models`, `native-static-libs`, `stack-protector-strategies`, `target-spec-json`, `link-args`, `split-debuginfo`
+
#![feature(unsized_locals)]
#![feature(unboxed_closures)]
+#![feature(tuple_trait)]
-pub trait FnOnce<Args> {
+pub trait FnOnce<Args: std::marker::Tuple> {
type Output;
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}
#![feature(unsized_locals)]
#![feature(unboxed_closures)]
+#![feature(tuple_trait)]
-pub trait FnOnce<Args> {
+pub trait FnOnce<Args: std::marker::Tuple> {
type Output;
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
}
string,
bool_val,
self,
- attribute,
+ attr,
macro,
question_mark,
comment,
("assert-css", ("pre.rust .string", {"color": |string|}, ALL)),
("assert-css", ("pre.rust .bool-val", {"color": |bool_val|}, ALL)),
("assert-css", ("pre.rust .self", {"color": |self|}, ALL)),
- ("assert-css", ("pre.rust .attribute", {"color": |attribute|}, ALL)),
+ ("assert-css", ("pre.rust .attr", {"color": |attr|}, ALL)),
("assert-css", ("pre.rust .macro", {"color": |macro|}, ALL)),
("assert-css", ("pre.rust .question-mark", {"color": |question_mark|}, ALL)),
("assert-css", ("pre.rust .comment", {"color": |comment|}, ALL)),
"string": "rgb(184, 204, 82)",
"bool_val": "rgb(255, 119, 51)",
"self": "rgb(54, 163, 217)",
- "attribute": "rgb(230, 225, 207)",
+ "attr": "rgb(230, 225, 207)",
"macro": "rgb(163, 122, 204)",
"question_mark": "rgb(255, 144, 17)",
"comment": "rgb(120, 135, 151)",
"string": "rgb(131, 163, 0)",
"bool_val": "rgb(238, 104, 104)",
"self": "rgb(238, 104, 104)",
- "attribute": "rgb(238, 104, 104)",
+ "attr": "rgb(238, 104, 104)",
"macro": "rgb(62, 153, 159)",
"question_mark": "rgb(255, 144, 17)",
"comment": "rgb(141, 141, 139)",
"string": "rgb(113, 140, 0)",
"bool_val": "rgb(200, 40, 41)",
"self": "rgb(200, 40, 41)",
- "attribute": "rgb(200, 40, 41)",
+ "attr": "rgb(200, 40, 41)",
"macro": "rgb(62, 153, 159)",
"question_mark": "rgb(255, 144, 17)",
"comment": "rgb(142, 144, 140)",
--- /dev/null
+// huge_logo crate has a custom 712x860 logo
+// test to ensure the maximum size in the layout works correctly
+goto: "file://" + |DOC_PATH| + "/huge_logo/index.html"
+
+size: (1280, 1024)
+// offsetWidth = width of sidebar
+assert-property: (".sidebar .logo-container", {"offsetWidth": "200", "offsetHeight": 100})
+assert-property: (".sidebar .logo-container img", {"offsetWidth": "100", "offsetHeight": 100})
+
+size: (400, 600)
+// offset = size + margin
+assert-property: (".mobile-topbar .logo-container", {"offsetWidth": "55", "offsetHeight": 45})
+assert-property: (".mobile-topbar .logo-container img", {"offsetWidth": "35", "offsetHeight": 35})
+
+goto: "file://" + |DOC_PATH| + "/src/huge_logo/lib.rs.html"
+
+size: (1280, 1024)
+assert-property: (".sub-logo-container", {"offsetWidth": "60", "offsetHeight": 60})
+
+size: (400, 600)
+assert-property: (".sub-logo-container", {"offsetWidth": "35", "offsetHeight": 35})
--- /dev/null
+goto: "file://" + |DOC_PATH| + "/test_docs/trait_members/struct.HasTrait.html#impl-TraitMembers-for-HasTrait"
+
+assert-count: ("#trait-implementations-list > .rustdoc-toggle", 1)
+
+compare-elements-css: (
+ // compare margin on type with margin on method
+ "#trait-implementations-list .impl-items > .rustdoc-toggle:nth-child(1) > summary",
+ "#trait-implementations-list .impl-items > .rustdoc-toggle:nth-child(2) > summary",
+ ["margin"]
+)
+
+compare-elements-css: (
+ // compare margin on type with margin on method
+ "#trait-implementations-list .impl-items > .rustdoc-toggle:nth-child(1)",
+ "#trait-implementations-list .impl-items > .rustdoc-toggle:nth-child(2)",
+ ["margin"]
+)
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
{"x": 951},
)
-
+// The tooltip should be beside the `i`
+click: "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']"
+compare-elements-position-near: (
+ "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
+ "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']",
+ {"y": 2}
+)
+compare-elements-position-false: (
+ "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
+ "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']",
+ ("x")
+)
+// The docblock should be flush with the border.
+assert-css: (
+ "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']/*[@class='docblock']",
+ {"margin-left": "0px"}
+)
// Now only the `i` should be on the next line.
size: (1055, 600)
"//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
{"x": 289},
)
+// The tooltip should be below `i`
+compare-elements-position-near-false: (
+ "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
+ "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']",
+ {"y": 2}
+)
+compare-elements-position-false: (
+ "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits']",
+ "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']",
+ ("x")
+)
+compare-elements-position-near: (
+ "//*[@id='method.create_an_iterator_from_read']/parent::*",
+ "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']",
+ {"x": 5}
+)
+// The docblock should be flush with the border.
+assert-css: (
+ "//*[@id='method.create_an_iterator_from_read']//*[@class='notable-traits-tooltiptext force-tooltip']/*[@class='docblock']",
+ {"margin-left": "0px"}
+)
// Checking on very small mobile. The `i` should be on its own line.
size: (365, 600)
// Example code blocks sometimes have a "Run" button to run them on the
// Playground. That button is hidden until the user hovers over the code block.
-// This test checks that it is hidden, and that it shows on hover.
+// This test checks that it is hidden, and that it shows on hover. It also
+// checks for its color.
goto: "file://" + |DOC_PATH| + "/test_docs/fn.foo.html"
-assert-css: (".test-arrow", {"visibility": "hidden"})
-move-cursor-to: ".example-wrap"
-assert-css: (".test-arrow", {"visibility": "visible"})
+show-text: true
+
+define-function: (
+ "check-run-button",
+ (theme, color, background, hover_color, hover_background),
+ [
+ ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+ ("reload"),
+ ("assert-css", (".test-arrow", {"visibility": "hidden"})),
+ ("move-cursor-to", ".example-wrap"),
+ ("assert-css", (".test-arrow", {
+ "visibility": "visible",
+ "color": |color|,
+ "background-color": |background|,
+ "font-size": "22px",
+ "border-radius": "5px",
+ })),
+ ("move-cursor-to", ".test-arrow"),
+ ("assert-css", (".test-arrow:hover", {
+ "visibility": "visible",
+ "color": |hover_color|,
+ "background-color": |hover_background|,
+ "font-size": "22px",
+ "border-radius": "5px",
+ })),
+ ],
+)
+
+call-function: ("check-run-button", {
+ "theme": "ayu",
+ "color": "rgb(120, 135, 151)",
+ "background": "rgba(57, 175, 215, 0.09)",
+ "hover_color": "rgb(197, 197, 197)",
+ "hover_background": "rgba(57, 175, 215, 0.37)",
+})
+call-function: ("check-run-button", {
+ "theme": "dark",
+ "color": "rgb(222, 222, 222)",
+ "background": "rgba(78, 139, 202, 0.2)",
+ "hover_color": "rgb(222, 222, 222)",
+ "hover_background": "rgb(78, 139, 202)",
+})
+call-function: ("check-run-button", {
+ "theme": "light",
+ "color": "rgb(245, 245, 245)",
+ "background": "rgba(78, 139, 202, 0.2)",
+ "hover_color": "rgb(245, 245, 245)",
+ "hover_background": "rgb(78, 139, 202)",
+})
("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
("reload"),
("assert-css", (".rust-logo", {"filter": |filter|})),
+ // Now we check that the non-rust logos don't have a CSS filter set.
+ ("goto", "file://" + |DOC_PATH| + "/huge_logo/index.html"),
+ // Changing theme on the new page (again...).
+ ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+ ("reload"),
+ // Check there is no rust logo
+ ("assert-false", ".rust-logo"),
+ // Check there is no filter.
+ ("assert-css", (".sidebar .logo-container img", {"filter": "none"})),
],
)
// We select "lib2" option then press enter to change the filter.
press-key: "ArrowDown"
press-key: "ArrowDown"
+press-key: "ArrowDown"
press-key: "Enter"
// Waiting for the search results to appear...
wait-for: "#titles"
click: "#crate-search"
press-key: "ArrowUp"
press-key: "ArrowUp"
+press-key: "ArrowUp"
press-key: "Enter"
// Waiting for the search results to appear...
wait-for: "#titles"
// Waiting for the search results to appear...
wait-for: "#titles"
assert-css: (
- "//*[@class='desc']//*[text()='Just a normal struct.']",
+ "//*[@class='desc'][text()='Just a normal struct.']",
{"color": "rgb(197, 197, 197)"},
)
assert-css: (
{"color": "rgb(0, 150, 207)"},
)
+// Checking the color of the bottom border.
+assert-css: (
+ ".search-results > a",
+ {"border-bottom-color": "rgba(170, 170, 170, 0.2)"}
+)
+
// Checking the color of "keyword" text.
assert-css: (
"//*[@class='result-name']//*[text()='(keyword)']",
)
// Checking color and background on hover.
-move-cursor-to: "//*[@class='desc']//*[text()='Just a normal struct.']"
+move-cursor-to: "//*[@class='desc'][text()='Just a normal struct.']"
assert-css: (
"//*[@class='result-name']/*[text()='test_docs::']",
{"color": "rgb(255, 255, 255)"},
// Waiting for the search results to appear...
wait-for: "#titles"
assert-css: (
- "//*[@class='desc']//*[text()='Just a normal struct.']",
+ "//*[@class='desc'][text()='Just a normal struct.']",
{"color": "rgb(221, 221, 221)"},
)
assert-css: (
{"color": "rgb(221, 221, 221)"},
)
+// Checking the color of the bottom border.
+assert-css: (
+ ".search-results > a",
+ {"border-bottom-color": "rgba(170, 170, 170, 0.2)"}
+)
+
// Checking the color for "keyword" text.
assert-css: (
"//*[@class='result-name']//*[text()='(keyword)']",
// Waiting for the search results to appear...
wait-for: "#titles"
assert-css: (
- "//*[@class='desc']//*[text()='Just a normal struct.']",
+ "//*[@class='desc'][text()='Just a normal struct.']",
{"color": "rgb(0, 0, 0)"},
)
assert-css: (
{"color": "rgb(0, 0, 0)"},
)
+// Checking the color of the bottom border.
+assert-css: (
+ ".search-results > a",
+ {"border-bottom-color": "rgba(170, 170, 170, 0.2)"}
+)
+
// Checking the color for "keyword" text.
assert-css: (
"//*[@class='result-name']//*[text()='(keyword)']",
wait-for: "#crate-search"
// The width is returned by "getComputedStyle" which returns the exact number instead of the
// CSS rule which is "50%"...
-assert-css: (".search-results div.desc", {"width": "318px"})
+assert-css: (".search-results div.desc", {"width": "310px"})
size: (600, 100)
// As counter-intuitive as it may seem, in this width, the width is "100%", which is why
// when computed it's larger.
// This is needed so that the text color is computed.
show-text: true
-// Ayu theme
-local-storage: {
- "rustdoc-theme": "ayu",
- "rustdoc-use-system-theme": "false",
-}
-reload:
-
-// Struct
-assert-css: (
- ".sidebar .block.struct a:not(.current)",
- {"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".sidebar .block.struct a:not(.current)"
-assert-css: (
- ".sidebar .block.struct a:hover",
- {"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-// Enum
-assert-css: (
- ".sidebar .block.enum a",
- {"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".sidebar .block.enum a"
-assert-css: (
- ".sidebar .block.enum a:hover",
- {"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-// Union
-assert-css: (
- ".sidebar .block.union a",
- {"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".sidebar .block.union a"
-assert-css: (
- ".sidebar .block.union a:hover",
- {"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-// Trait
-assert-css: (
- ".sidebar .block.trait a",
- {"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".sidebar .block.trait a"
-assert-css: (
- ".sidebar .block.trait a:hover",
- {"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-// Function
-assert-css: (
- ".sidebar .block.fn a",
- {"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".sidebar .block.fn a"
-assert-css: (
- ".sidebar .block.fn a:hover",
- {"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-// Type definition
-assert-css: (
- ".sidebar .block.type a",
- {"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".sidebar .block.type a"
-assert-css: (
- ".sidebar .block.type a:hover",
- {"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-// Keyword
-assert-css: (
- ".sidebar .block.keyword a",
- {"color": "rgb(83, 177, 219)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".sidebar .block.keyword a"
-assert-css: (
- ".sidebar .block.keyword a:hover",
- {"color": "rgb(255, 180, 76)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-
-// Dark theme
-local-storage: {"rustdoc-theme": "dark"}
-reload:
-
-// Struct
-assert-css: (
- ".sidebar .block.struct a:not(.current)",
- {"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".sidebar .block.struct a:not(.current)"
-assert-css: (
- ".sidebar .block.struct a:hover",
- {"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
-)
-// Enum
-assert-css: (
- ".sidebar .block.enum a",
- {"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".sidebar .block.enum a"
-assert-css: (
- ".sidebar .block.enum a:hover",
- {"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
-)
-// Union
-assert-css: (
- ".sidebar .block.union a",
- {"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".sidebar .block.union a"
-assert-css: (
- ".sidebar .block.union a:hover",
- {"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
+define-function: (
+ "check-colors",
+ (
+ theme, struct, struct_hover, struct_hover_background, enum, enum_hover,
+ enum_hover_background, union, union_hover, union_hover_background, trait, trait_hover,
+ trait_hover_background, fn, fn_hover, fn_hover_background, type, type_hover,
+ type_hover_background, keyword, keyword_hover, keyword_hover_background,
+ ),
+ [
+ ("local-storage", { "rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false" }),
+ ("reload"),
+ // Struct
+ ("assert-css", (
+ ".sidebar .block.struct a:not(.current)",
+ {"color": |struct|, "background-color": "rgba(0, 0, 0, 0)"},
+ )),
+ ("move-cursor-to", ".sidebar .block.struct a:not(.current)"),
+ ("assert-css", (
+ ".sidebar .block.struct a:hover",
+ {"color": |struct_hover|, "background-color": |struct_hover_background|},
+ )),
+ // Enum
+ ("assert-css", (
+ ".sidebar .block.enum a",
+ {"color": |enum|, "background-color": "rgba(0, 0, 0, 0)"},
+ )),
+ ("move-cursor-to", ".sidebar .block.enum a"),
+ ("assert-css", (
+ ".sidebar .block.enum a:hover",
+ {"color": |enum_hover|, "background-color": |enum_hover_background|},
+ )),
+ // Union
+ ("assert-css", (
+ ".sidebar .block.union a",
+ {"color": |union|, "background-color": "rgba(0, 0, 0, 0)"},
+ )),
+ ("move-cursor-to", ".sidebar .block.union a"),
+ ("assert-css", (
+ ".sidebar .block.union a:hover",
+ {"color": |union_hover|, "background-color": |union_hover_background|},
+ )),
+ // Trait
+ ("assert-css", (
+ ".sidebar .block.trait a",
+ {"color": |trait|, "background-color": "rgba(0, 0, 0, 0)"},
+ )),
+ ("move-cursor-to", ".sidebar .block.trait a"),
+ ("assert-css", (
+ ".sidebar .block.trait a:hover",
+ {"color": |trait_hover|, "background-color": |trait_hover_background|},
+ )),
+ // Function
+ ("assert-css", (
+ ".sidebar .block.fn a",
+ {"color": |fn|, "background-color": "rgba(0, 0, 0, 0)"},
+ )),
+ ("move-cursor-to", ".sidebar .block.fn a"),
+ ("assert-css", (
+ ".sidebar .block.fn a:hover",
+ {"color": |fn_hover|, "background-color": |fn_hover_background|},
+ )),
+ // Type definition
+ ("assert-css", (
+ ".sidebar .block.type a",
+ {"color": |type|, "background-color": "rgba(0, 0, 0, 0)"},
+ )),
+ ("move-cursor-to", ".sidebar .block.type a"),
+ ("assert-css", (
+ ".sidebar .block.type a:hover",
+ {"color": |type_hover|, "background-color": |type_hover_background|},
+ )),
+ // Keyword
+ ("assert-css", (
+ ".sidebar .block.keyword a",
+ {"color": |keyword|, "background-color": "rgba(0, 0, 0, 0)"},
+ )),
+ ("move-cursor-to", ".sidebar .block.keyword a"),
+ ("assert-css", (
+ ".sidebar .block.keyword a:hover",
+ {"color": |keyword_hover|, "background-color": |keyword_hover_background|},
+ )),
+ ]
)
-// Trait
-assert-css: (
- ".sidebar .block.trait a",
- {"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".sidebar .block.trait a"
-assert-css: (
- ".sidebar .block.trait a:hover",
- {"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
-)
-// Function
-assert-css: (
- ".sidebar .block.fn a",
- {"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".sidebar .block.fn a"
-assert-css: (
- ".sidebar .block.fn a:hover",
- {"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
-)
-// Type definition
-assert-css: (
- ".sidebar .block.type a",
- {"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".sidebar .block.type a"
-assert-css: (
- ".sidebar .block.type a:hover",
- {"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
-)
-// Keyword
-assert-css: (
- ".sidebar .block.keyword a",
- {"color": "rgb(253, 191, 53)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".sidebar .block.keyword a"
-assert-css: (
- ".sidebar .block.keyword a:hover",
- {"color": "rgb(253, 191, 53)", "background-color": "rgb(68, 68, 68)"},
-)
-
-// Light theme
-local-storage: {"rustdoc-theme": "light"}
-reload:
-// Struct
-assert-css: (
- ".sidebar .block.struct a:not(.current)",
- {"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".sidebar .block.struct a:not(.current)"
-assert-css: (
- ".sidebar .block.struct a:hover",
- {"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
-)
-// Enum
-assert-css: (
- ".sidebar .block.enum a",
- {"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".sidebar .block.enum a"
-assert-css: (
- ".sidebar .block.enum a:hover",
- {"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
-)
-// Union
-assert-css: (
- ".sidebar .block.union a",
- {"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".sidebar .block.union a"
-assert-css: (
- ".sidebar .block.union a:hover",
- {"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
-)
-// Trait
-assert-css: (
- ".sidebar .block.trait a",
- {"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".sidebar .block.trait a"
-assert-css: (
- ".sidebar .block.trait a:hover",
- {"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
-)
-// Function
-assert-css: (
- ".sidebar .block.fn a",
- {"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".sidebar .block.fn a"
-assert-css: (
- ".sidebar .block.fn a:hover",
- {"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
-)
-// Type definition
-assert-css: (
- ".sidebar .block.type a",
- {"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".sidebar .block.type a"
-assert-css: (
- ".sidebar .block.type a:hover",
- {"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
-)
-// Keyword
-assert-css: (
- ".sidebar .block.keyword a",
- {"color": "rgb(53, 109, 164)", "background-color": "rgba(0, 0, 0, 0)"},
-)
-move-cursor-to: ".sidebar .block.keyword a"
-assert-css: (
- ".sidebar .block.keyword a:hover",
- {"color": "rgb(53, 109, 164)", "background-color": "rgb(255, 255, 255)"},
+call-function: (
+ "check-colors",
+ {
+ "theme": "ayu",
+ "struct": "rgb(83, 177, 219)",
+ "struct_hover": "rgb(255, 180, 76)",
+ "struct_hover_background": "rgba(0, 0, 0, 0)",
+ "enum": "rgb(83, 177, 219)",
+ "enum_hover": "rgb(255, 180, 76)",
+ "enum_hover_background": "rgba(0, 0, 0, 0)",
+ "union": "rgb(83, 177, 219)",
+ "union_hover": "rgb(255, 180, 76)",
+ "union_hover_background": "rgba(0, 0, 0, 0)",
+ "trait": "rgb(83, 177, 219)",
+ "trait_hover": "rgb(255, 180, 76)",
+ "trait_hover_background": "rgba(0, 0, 0, 0)",
+ "fn": "rgb(83, 177, 219)",
+ "fn_hover": "rgb(255, 180, 76)",
+ "fn_hover_background": "rgba(0, 0, 0, 0)",
+ "type": "rgb(83, 177, 219)",
+ "type_hover": "rgb(255, 180, 76)",
+ "type_hover_background": "rgba(0, 0, 0, 0)",
+ "keyword": "rgb(83, 177, 219)",
+ "keyword_hover": "rgb(255, 180, 76)",
+ "keyword_hover_background": "rgba(0, 0, 0, 0)",
+ }
+)
+call-function: (
+ "check-colors",
+ {
+ "theme": "dark",
+ "struct": "rgb(253, 191, 53)",
+ "struct_hover": "rgb(253, 191, 53)",
+ "struct_hover_background": "rgb(68, 68, 68)",
+ "enum": "rgb(253, 191, 53)",
+ "enum_hover": "rgb(253, 191, 53)",
+ "enum_hover_background": "rgb(68, 68, 68)",
+ "union": "rgb(253, 191, 53)",
+ "union_hover": "rgb(253, 191, 53)",
+ "union_hover_background": "rgb(68, 68, 68)",
+ "trait": "rgb(253, 191, 53)",
+ "trait_hover": "rgb(253, 191, 53)",
+ "trait_hover_background": "rgb(68, 68, 68)",
+ "fn": "rgb(253, 191, 53)",
+ "fn_hover": "rgb(253, 191, 53)",
+ "fn_hover_background": "rgb(68, 68, 68)",
+ "type": "rgb(253, 191, 53)",
+ "type_hover": "rgb(253, 191, 53)",
+ "type_hover_background": "rgb(68, 68, 68)",
+ "keyword": "rgb(253, 191, 53)",
+ "keyword_hover": "rgb(253, 191, 53)",
+ "keyword_hover_background": "rgb(68, 68, 68)",
+ }
+)
+call-function: (
+ "check-colors",
+ {
+ "theme": "light",
+ "struct": "rgb(53, 109, 164)",
+ "struct_hover": "rgb(53, 109, 164)",
+ "struct_hover_background": "rgb(255, 255, 255)",
+ "enum": "rgb(53, 109, 164)",
+ "enum_hover": "rgb(53, 109, 164)",
+ "enum_hover_background": "rgb(255, 255, 255)",
+ "union": "rgb(53, 109, 164)",
+ "union_hover": "rgb(53, 109, 164)",
+ "union_hover_background": "rgb(255, 255, 255)",
+ "trait": "rgb(53, 109, 164)",
+ "trait_hover": "rgb(53, 109, 164)",
+ "trait_hover_background": "rgb(255, 255, 255)",
+ "fn": "rgb(53, 109, 164)",
+ "fn_hover": "rgb(53, 109, 164)",
+ "fn_hover_background": "rgb(255, 255, 255)",
+ "type": "rgb(53, 109, 164)",
+ "type_hover": "rgb(53, 109, 164)",
+ "type_hover_background": "rgb(255, 255, 255)",
+ "keyword": "rgb(53, 109, 164)",
+ "keyword_hover": "rgb(53, 109, 164)",
+ "keyword_hover_background": "rgb(255, 255, 255)",
+ }
)
// Only "another_folder" should be "open" in "lib2".
assert: "//*[@class='dir-entry' and not(@open)]/*[text()='another_mod']"
// All other trees should be collapsed.
-assert-count: ("//*[@id='source-sidebar']/details[not(text()='lib2') and not(@open)]", 5)
+assert-count: ("//*[@id='source-sidebar']/details[not(text()='lib2') and not(@open)]", 6)
// We now switch to mobile mode.
size: (600, 600)
// Checks that the interactions with the source code pages are working as expected.
goto: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
+show-text: true
// Check that we can click on the line number.
click: ".src-line-numbers > span:nth-child(4)" // This is the span for line 4.
// Ensure that the page URL was updated.
assert-attribute: (".src-line-numbers > span:nth-child(5)", {"class": "line-highlighted"})
assert-attribute: (".src-line-numbers > span:nth-child(6)", {"class": "line-highlighted"})
assert-attribute-false: (".src-line-numbers > span:nth-child(7)", {"class": "line-highlighted"})
+
+define-function: (
+ "check-colors",
+ (theme, color, background_color, highlight_color, highlight_background_color),
+ [
+ ("local-storage", {"rustdoc-theme": |theme|, "rustdoc-use-system-theme": "false"}),
+ ("reload"),
+ ("assert-css", (
+ ".src-line-numbers > span:not(.line-highlighted)",
+ {"color": |color|, "background-color": |background_color|},
+ ALL,
+ )),
+ ("assert-css", (
+ ".src-line-numbers > span.line-highlighted",
+ {"color": |highlight_color|, "background-color": |highlight_background_color|},
+ ALL,
+ )),
+ ],
+)
+
+call-function: ("check-colors", {
+ "theme": "ayu",
+ "color": "rgb(92, 103, 115)",
+ "background_color": "rgba(0, 0, 0, 0)",
+ "highlight_color": "rgb(112, 128, 144)",
+ "highlight_background_color": "rgba(255, 236, 164, 0.06)",
+})
+call-function: ("check-colors", {
+ "theme": "dark",
+ "color": "rgb(59, 145, 226)",
+ "background_color": "rgba(0, 0, 0, 0)",
+ "highlight_color": "rgb(59, 145, 226)",
+ "highlight_background_color": "rgb(10, 4, 47)",
+})
+call-function: ("check-colors", {
+ "theme": "light",
+ "color": "rgb(198, 126, 45)",
+ "background_color": "rgba(0, 0, 0, 0)",
+ "highlight_color": "rgb(198, 126, 45)",
+ "highlight_background_color": "rgb(253, 255, 211)",
+})
+
// This is to ensure that the content is correctly align with the line numbers.
compare-elements-position: ("//*[@id='1']", ".rust > code > span", ("y"))
// Now let's check that clicking on something else than the line number doesn't
// do anything (and certainly not add a `#NaN` to the URL!).
-show-text: true
goto: "file://" + |DOC_PATH| + "/src/test_docs/lib.rs.html"
// We use this assert-position to know where we will click.
assert-position: ("//*[@id='1']", {"x": 104, "y": 112})
// We check that the first entry of the sidebar is collapsed
assert-property: ("#source-sidebar details:first-of-type", {"open": "false"})
-assert-text: ("#source-sidebar details:first-of-type > summary", "implementors")
+assert-text: ("#source-sidebar details:first-of-type > summary", "huge_logo")
// We now click on it.
click: "#source-sidebar details:first-of-type > summary"
assert-property: ("#source-sidebar details:first-of-type", {"open": "true"})
--- /dev/null
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "huge_logo"
+version = "0.1.0"
--- /dev/null
+[package]
+name = "huge_logo"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
--- /dev/null
+// ignore-tidy-linelength
+#![doc(html_logo_url = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAsgAAANcCAQAAADoIpEcAAAAAmJLR0QA/4ePzL8AAHSISURBVHja7Z15vFbT/sefzNflXtzr+qHOXvs5p051KtVJIg1IhqRoQlHKVKbKUBkaRQiRpEhKkqIQkURyJJUkQxNKs4bTPJ7h8/uj5Ax772fvZ6+999r7+bzXP14vPXufs9b3+znr+a7v+n5jMUIIIYQQ95zxTz1Tr6e10Dpp3bX+4nkxRrwnZonvxW/iN/Gb2CpyRa7YIyAgIHaLXJErcsVqsUxfoM0QU7Sx+ouij9ZFuyZ+oZ6ZeTLnkxBCbJJ1XLy8uEx01p4Wb4vZYrnYfVhqZY1csVC8qz+j3y0u1zXONyGEFCPt1PiF4nZtqJgpVol8yQJsObRdYp4YrT+gXZTxL64DISRlySirXSsGielirZ8SbDoKxBJtrH63qB47imtDCEkJxAnaRdrD4j2xXgkZNg5qvCe6UpgJIdHlmLRs0UObIfYpK8QlwxmbxUT9pvi/uXSEkMig6frdYnp4hLjE2C+m67ee/R+uIyEkzBwVv1AMEj+FVIiLj4PiI/0mHvwRQkJIWpboK36LhBQXHfvExHijWBmuLyEkFIiK+sAISnHR8YvolnYqV5oQojAZx+uttBmiMNJi/Hf+8ghRkWtOCFFyXyyeF7mpIMXFMpenaBdw7QkhChG/UEz0936dSkPPEQ1pA4SQwMk+Vr9RfJ+qUlxkTIufS2sghAQpxjdpKyjGh0ehmKjptApCiP8cpbcSyynDJcYB8Tzv9RFCfEW7Riyj/JqM9XprWgghxB8xriG+oOwmGJ/HK9BSCCGeIv5PvCYKKLg2xh6tO2vFEUK8oox+k9hCqXUwvk7PoNkQQqSjZ4ovKbGOxw5xM22HECKTo7WHQls6M/gxPuskmhAhRM7eWOPe2OVYGq9KOyKEuEa0Fzsoqa7Hbq0tbYkQ4oKsk8QEiqm08QSzLgghSRKvoP1IGZU6PmK/EUJIEmgtxE5KqPSxqNxZtC1CiBPK6I+lRpH5AMbv8fI0MEKITTKO18dROD0cW0QdWhkhxAYV/qvnUDS9vi6i16OlEUISIARLavrTj4+STAixJF5BrKZY+lZ86CJaHCHETI6rig0USj93ydr5tDpCiAFaTVZy833kpleh5RFCSqBnio0UyADGOnbhI4QUD1aUZ7AisLE843RaICHkMELwKC/IoedkHE8rJITEYrGyp4mlFMWAx4RYGVoiISlPxvGsdaxExsXDtEVCUp0y2liKoRKjUDSnORKS0oi+lEJ1UuCYb0FICqM3FQUUQpVKc551Iq2SkJQkXkFspwgqNkbQLglJQbJOYjcQJVPgWtM2CUm96PEYip+akeR4Gq2TkNSS4zaUPmXHTLZCJSSFyCgrtlL4FA5b3EUbJSRVOErMpugpXpaTCXCEpEi4ohslT/nxOa9SE5ICpMXFbgpeCHbJnWirhESdMuJTil0oxtYK/6W5EhJp9FsodaHZI79CeyUkyuGKU8UmCl1oRgE77hES5f3xMMpcqPbI85mRTEhESa+i5VHkQpaRfCPtlpBIwkL0IRyry/6DlktI5IhfRXljJxFCiAocLX6iuIVybE87leZLSKTQOlLaQjv60H4JiRBZx4k/KGyhHdvi/6YNExIZ9Fspa6EevWnDhEQnfrycohbuOLI4hWZMSCQQ7Slpoc9HfoR2TEgUKCN+oaCFv9RQxr9oyoSEHq0J5SwS+cgP0ZYJCX/AYibFLBJjffaxtGZCQk28qiikmEVktKE9ExLu/fFrFLLIBC2+oj0TEub98b/FHgpZdEZaNm2akNCi300RYw8RQogSaD9SxCI19p79H1o1IeGU4wsoYZHbI99HuyYklIiXKWCRG7+xqRMhISTrOLGFAhbB0ZC2TUj4AhYtKF482COEqBGwmELximZ1ZHECrZuQUJF5sthH8Ypo5beWtG9CwhWwuIHCFdkxhfZNSKjQ36FwRXYcYDYyISHirBPFbgpXhMfttHFCwrM/vpqiFekxmzZOSHgEeRhFK9KjsOzZtHJCQoL4laLFoAUhRAE0nYIV+dS3D2nnhIRjf9yZghX5sT/rJFo6IWEQZN7RS4XRjJZOiPocI7ZTrlIgaPEqTZ0Q5dHrUaxSYvzJQpyEKI82gGKVIuM8WjshqkeQZ1OqUiRo8RitnRClyT6WfaZTZsylvROidsCiJoUqZUrV52X8ixZPiMoBC+Ygp5IkN6HFE6KyIL9OmUqhKPJgWjwhKgvyUspUCo3vaPGEqCvHp4gCylQKjYK0U2n1hKgqyJdRpHiBmhCihiD3pkSl2BhCqydEVUGeTIlKsbGIVk+IqoK8jBKValHkzJNp94QoSMbxWh4lKuVGA1o+IQqin0N5SsFc5Ado+YQoiHYD5SkFx0RaPiEq7pAfozyl4FhFyydEQdi6KUWDFmfQ9glRT5CZY5GagtyUtk+IanJ8gsinOKVkzbf+tH5CFCMti9KUouNjWj8hiqFdSWlK0bGW1k+IaiELlqZP2XH2f2j/hKglyIMoTCl7rFef9k+IWoL8FoUpZY/1utD+CVFLkOdQmFJ2vET7J0QtQV5HYUrZHfJXtH9CFCLrODZvSuGxPVaGPkCIMpRLpyyl8sgoSx8gRJ2ARQOKUkoHLa6gDxCiDHprilJKj3voA4Qog3YnRSlhti7qoAXaojO6oAs6oA0aoEJUfrvn6QOEqBOy6EvBNRuX4FG8g+U4ACPWYjoGowXSw/3H5kP6ACHqCPJLFF4jKR6O32GPXLyD66CH9XddSh8gRJ2QxSTKb/HwRGfMRSGcshL9UCmMv/GB2NH0AkJU2SHPogj/PW7FL0ieLXgcmeH7rQW9gBBVBPlnyvCh0RBfwj3r0T1kv3e8Eb2AEFVCFpspxQIZeAEHIYvPUDtMv/0d9AJC1OAotm8SaIBFkEsu7grP1ZCn6QaEKEHmyZTjztgNLxgXllzlifQDQtQIWJwpOR6JZngaH2MZcgEAediM7zEJPXCBmvFTDE0io8Iui1AnDII8h35AiBLEK8hz7Dp4ERtNxakQC/GAYjkIFTAN3rIBjdUPWayhHxCixg65phynzsYY5NkQqM3ojQxFhKgyvoL37EAb1SU5P3YMPYEQBZBT663L4QCFPVbheiXkeAH8Ya/ykswSnISosUNu4l7YPnAsUQUYHnAFiPKYBf/Yi9ZqBy3OpycQosIO+Tp3rlwXS5IUqfmoFeBR3nT4y3ZcovJ18Vb0BEIUQL/FjSNfjPWuDryuDEiAhsF/ViNb3R1yd3oCISrskLsm78aNsMX1gVfzAOTnLg8T3ayYq26hzmfpCYSoIMg9k3Xi+tggQaR2oYXP4lPfo2sgdnheVUEeT08gRIWQxaPJuXAVLJckUrtwha81KxYhOAqUyC8xiCF/Rk8gRAG0/sk4cDpmS7084d99tucRLGtRWUVJXkxPIESFkMUTyTjwc5Jl6nufqj5cZNKMyU9GqyjIG+kJhKgQsnjGuftea+tOnjPG+NIL5BsET0EgB5kJ7+odRV8gJPiQxQvOr1Ss8ESobvZcdu6BGixUsP9exun0BUKCD1kMd+q6T3kkUxtxjsd381ZBFdSrlZxWmb5ASPCCPMppESHvksbe8FRy+kAdVqO8apLckL5ASPAhi7HOHHeMp9HVZp4JTkVshkr0VC3xrTV9gZDgBfkNJ257vsS+c0bM8UxwekMt/lDt1l5n+gIhIdshj/RcqLypipaOP6Aa96lVzeIh+gIhwceQxzi5nbfLc5n62qPqFerxi1o75CfpC4QEL8iv23faHr4IlRd75HlQEaXK1o+gLxASvCCPtu+0/lyryJEuNo2hJh+rJMhv0xcICV6QX7N/oFfgk1A1kSw2YxQV5LwAS/SXGp/SFwgJXpBt5yE/6ZtQyb1GneGo35+/DFBHkOfRFwgJHP1Vuy671DeZ2olKEqXmZkk50ovxKcbhNXyKn6WVKFLoYG85fYGQwNFesdusyU+6SpSaKa5/msXojprFnlkV3ZAj5TdtpIogb6IvEBJ8yOIlFS9WzJGYgbzD1U+yCreYlgJqj19d/6ZPqSLIB+gLhAQvyEPsOezHvgpyIRpIEprWrn6Oj1AtQcGiSa4rQasStMg+lt5ASNAhi6fs7TO3+Xzc1T/w/tIF6G3zsLPQ1Z8eVXpRx/9NbyAkYPTH7DhrU9/zD76UJDOLk3x/PrrZfsdjrn7TOxUR5HJn0RsICTpk0duOsw5Kaoe5DhuSzkfYLyXTolKSvU0KHR4ruqnxMU6VHXJ5egMhQQtyTzvOOs2hFH+Ctsg65OZogTFJyXJHCSLTJkmRHOG4OdQXSQvyClWiyNXpDYQEHUPubsdZlzsQmDW4ttTn6ybRpVrG9ZBBSUlkThKlMc9LOspecPhPV+A9Q+rSGwgJOoZ8l527bva/+P9o0ogpjucdCtWvEkTmvSQEcg8uSOpdXZPeI7dSo0R9Y3oDIUEL8i2JXbWRAxGtafGcAQ53jpVdi8wvScjjoKTftihJQe6rRkXka+kNhAQdsmib2FU72xSWfWic4EnPOBKqa1xfCtnvWBx/ddHt7qYkBfkNNXbI7egNhAQtyNckdtXBNoWlt43Dr88cCNVDLiXmwiTEsZurN85XpOBoUjvkjvQGQoIOWTSWVb5yma2jsHOwybedYyvH0rgeGa7eeG9SgryaXfUIIbFYLBa/MLGrfmBLVm636fjdbQvVApcSc7djaezj8o2Z2J7UJRQlGp52pTcQEnTIokZiV51lqwiPbjtnd4FNodruUmKc3qDbKyEBLbli+EoUqu9BbyAk6JBFZmJX/cGGpAz25PDL3W29oQ5l8T0JstYiKUG+XAVB7k1vICRgMsomdtWVNiSlricVJuq5kpjXHcpiBynlPpPpT9JWhSyLgfQGQgKm7GmJXTXXxoGeN4df17qSmMmORDFXUiT3/SQE+Q4VBPkZegMhAZN1XGJXTXwp+BXHh187fBAqZxU4PpQkbN2TEORuKgjyi/QGQgJH7E3kqps9KAQ03pZQPepKYj51JIoPSxK2ZJpdPaRCDHkEfYGQ4AX5z0SuusGDLIEbbAnV864k5jNHonixrDKW2O1YkJ9Q4WLIK/QFQoIX5OWJXHVtAjnZkIT7Z2CnB2Uwi4+ZjiLI8qTtW8eCPESFHfIo+gIhgaPNd5tlMcuzCO/rvgnyfInSNs6xIA9WQZBH0xcICX6HPDORq65IICdvJiUAfWwI1Zu+HepNkChtzzgW5CdVEOQx9AVCghfkyW4vhjyblABcY0Oo3nElMU46Qj8mUdoedCzIA1WIIb9BXyAkeEEe7fZwrGeSdR8Sl73/wLdrzDJbjbZ3LMi9VNghv0lfICR4QX7ebYpaslm0vycUqimuJGZYQHflWoaz8/Rb9AVCAkfrn8hVhySQk7uSlIDEjUHddWTu70ASm0iUtmscC3I7FQT5bfoCIYGj35/IVR/y6D5d4pDCSFcSc6cDSbxQorRd5ViQr1Lhpt479AVCghfkWxO56i0J5KRrkhLwlMf5uU5CBzUkStsVjgW5pgo75Mn0BUKCjyG3SeSqTRLIySNJSkDfhEL1uCuJqeOgXLxMSbzeoRzvs11L2tPxHn2BkOAF+XK3+RDJ9mnuYVksfjruQzXX15ivwkB8buMy83kSpa2zQ0H+XY0WTh/QFwgJHO38xM66zFJQXk5SAu4xfFoB5uA+VJYqNulog5H4zacY8kMOBfkzNbpOf0hfICRw0rISO+sUS0GZmqQE3FrqSZsxxGGpe2ejAQbgGxQY/A4NJb7lKYeCPEyNHfI0+gIhgWOnZ8hAS0FZlKQEdCz2lCW4HxV8kZ46GIifSvwOzSU+f7RDQb5XDUGeTl8gJHCyTkrsrO08qZTW7cgTfrFZUbkyLsdt6I9hGIXx+BAfYSrGYwyGYwA6o6mjo7lGGIp1nlzN+NKhIF+qhCBrM+gLhCiAOJjIWasbfs3/mzouLm6sxF2IW/67LNyAwfgMf9oQtz2Yj9HohkYJnvnXoV8n5EjI5yg+1jmS4+22flIfxkx6AiEqCPKmxO66yFJUbkuyK/R+DLEMU9RHf8yxUfPCiF2Yjl64wMbP0RSTMUqasFVGoaOfc6YacgzxKT2BEBUEeVlid7W+Pv1iklkWDUz/X1U8ip8hg2UYYSNCnClN2FqFsfQmBMTH9ARCVBDkb93WZ1gkVRqaYjz2QC6/YQjq+yJsQxz+ZE0UEWSmvRGihiB/YieTN9dCVAqS6KpnlnmxGF5RgDno7nkmxzxHP9OfatzS48UQQpQR5LfsOOz7lsLygJSylXPhPVswRGrlipIR5IOOfpq3VZFjiCn0BEJUEOThdhz2dkth+dp1mOIr+MdevCH1Ksjfo6vDn+RmZQSZ1d4IUUOQH7d3/XiThbAUuojQVsaryIffFGAaGkmXtVmOfoZcZKizQ2Y9ZEKUEOQH7bnsCEtxGZqkEHTAGgRFAT6yyPRwPrIdpui9oY4cs2MIIWqQuCLyoXGRZYbtTlR1LAJVE1TJ8IMDGI1sSaL2tMN3t1BIkPVx9ARCVBDkVnaddr6lvDzhUAKuxh9Qgz0YgooS9sfbHL11iUr7Y4gx9ARCFCDeyHn1CeOIqJPshV4O8xG85g+b9TTMr2F/6vCNj6olyK/REwhRQZBr2XXajATx3rdsH+NNh4p86qIu8gjHV7urKCXI+qv0BEIUoFy6fbd9JMEh2Q22yl/+mECs8vEtnsGduBpN0RYP4ytH9SE2YCg6oiWuwo3ojSmOAgn7MCSpa9R9HIv/y2rtjyFG0BMIUYCM0+27bQVsSHDtIlHlt5bYYvmElRhgcMh2m+0Ax7RSd/HScRM+TVCvrnhLpfaOe4QUOpTjA1KbRkkZL9ETCFEAcYLzopnmLLbshHcPDlh8diPuNy1G+blNqatjWv/YSY7wdNSzPSO9HcsxME41OYY2lJ5AiBqSfNDJHvn3BGLzo+nhXh/Lfeosi6hqA+yQUD3tQQcXUPbheVuJfN0c7L3/Yr+tsqA+j+fpB4SoIci5ybdeMuJXXGLwuUGWn1mDSoZvq4J2eMtR9bd5eND03uBQR8K5G8NxToLZaIxhjq+2DFdPjiGepR8QooYgr3bmvJ8lEJwfSrUqjWNcgs+MNris3RPfJn2pej1exfkG8umUnRhm8JzStThGY7PtC9NVFRRk7Wn6ASFqCPLPzpy3PvZZCM6oUhUa0jExoUx9WeIz9fC96zS2Xehe6nAwuSvWOeiC9IRJgR0xBXsTPu0RFffHEIPoB4SoIchznbrvw6Z33u4yEKoPbZairFHk8G8b5PD2kUPGOLpaVnVOfHVkiI3KF1XQC79YPOU7VXrolRyP0w8IUQJthnMHnmIYO25scAg4w7bk5WE+JuA1yUXqczERYzANWyU8qxAL8IiNG4lNMd5wr3zAgwpzkkIWA+gHhKixQ57s3IGzsLKE2ExB5VL/qhJmI3rkIwfdkZWwV/cA/FrikwMVlWMB0Zd+QIgaO+SxybhwY2wvUvK9h2G5nfmILnsxFbcmaAml4zq8fyT3eqY6DZtKj970A0KUQB+WnBM3w24AwApcZvi1fT2iz3ZMwA0J4sLZGIJcrPOwdZSEkMXD9ANC1AhZDEq+D94eTDbMIH4E+5E6bMCLuMhypiqqeBmk6OhJPyBEjZDFw8k78nmGheenIhVZjH5K74ItgysP0A8IUWOH3FWma7fEOqQuezEJzUIoyNp99ANC1Igh3yXLreMY7LCvXFT3yj0Mck6UHl3pB4SosUO+XY5Tn4scanGRS9evK5t1bBCyuJt+QIgaMeSOMlz6BvxJFS7FfHRSOdnt75BFF/oBIWqELG50687peDGJMpSpwlJ0Vl+U76AfEKJGyOI6d858fqQvgMjhe1yntiDfTj8gRI0dcms3rtzJVcmeVOIjg+ZU3CETQorHkNsm68bl8WoSDYxSl224V1VB7kw/IESNkEWH5Jy4Lr6jxjpmsklvlIAP9e6kHxCixg65UzIufCd2Ul2TzFKuxbQ3QojJDvkOp+6bidHUVResRkNenSaEGAryPc6c9xIspaa6LkekWLGhvvQDQtQIWfR34rr3O+oBTcxYoVQhIjY5JUSVHfJwu25bGZOppNL4XKHrIvow+gEhauyQJ9lz2jr4mSoqlcfU2SG/QT8gRI0d8pd2XLYpNlJBJbMX56siydPoB4SoIcg/J3bYy7CD+ukB76siyPPoB4SoIcibEgcr1lM7bVKId9ERbfEoltj41wVooIYg/0Y/IEQFjhL5iWq5/UidtUk+7izS3soOr6ohyDvoCIQogHZmImcdTJ21zePFuk3bYaMiuRaZJ9MXCAmctGxrR62HA9RZm8wsJq6P2fzU1WrkWVSiLxASOHpTa0d9jTpr+/Zd0aseNbDF5uf6qJGJ3Ji+QEjgWHfUq4JdVFpb5KFNUXnDdNuffFuNHXIn+gIhwQtyX+uabqWZjevwNDZTg4tlSxSvdPyCg89+qYYgD6AvEBI42kgrNx1rkNZV+/BX8kXU4cMcRPdis9bDUdn+xWrkWUygLxASfAz5Qys3LZ1L+8eR/1eTfaYBALkl+uV1d9jwVRFB/p6+QEjwO+Qfrdy0dL+8VUX+bxeqMeajTrEZexD5jp+ghCDvjpWhNxAStCDvMnfSuIG4HEBmkX+R2v2mC/EaMorNWN8kegx+qMj16fRy9AZCAiXjdOvOIEYU/YLeIoXleDPalbjROCqp57ysSsW3JvQHQoKNINe2dlKjYvQfFfsXH6SoHOfg3GLzUA2zknzS3aoI8kP0B0KCFeTW1k662rBeQ+Mi/6IWNqRgxYpnEC82Txfh16SfpkwJzrfpD4QEiuhh7aQ5hhLyCyoU+TdXGBz9RftGXusSs9QO25N+2q/qNHJaRn8gJFhBftnaSc0uOEwqtkNslEK75M9L9cLrizwXzxuqjiAXVvgvPYKQIAX5c2snvdFUSD4oll9QF7+nxPXo50qEKrLwvstnNlap93QzegQhQQry+kRtTc17TM8olgBXK/Id91aheYnZuRIrXT7zG5XkGPpgegQhgZHxr8ROOslCTuaiSrE8gyhnJb+LrBIz0w17XT/1VqUEWXxLnyAkuP3xeYmdtE2Ca79FI6qV8EVEL0ffXqoK3lQJz12sSHH6I4lveVkn0SsICUqQ29v4GotllqKyotjV4QzLHXU4mXW4nNLf42rXoYpD3KTW/hgCaZfQKwgJSpAft+OktyWQlTVoWEzAh0ZIjPegd4ldbHkMdZVV8TcfKyfHAqIvvYKQoAR5iq2jHixMeIn4ymKf6CVJsoLm01KXNprY6iVth90lihIpMj6nVxASlCCvtOemrRKWzNmDDtKuSqjBRnQr1X17EA5Ke/4DKsoxxD5GkQkJRo5PEYV2HfV1Gzm6PYt9ogFWhFaMCzC+VE5FYyyW+IZpasoxBLRr6RmEBIB2kX03rWTj4kchBpcot/NlSA/xLi+Vjf2SxL0x8CuqKivIYgw9g5AgBLm7E0e9xlZceEqxyyLpeN5h94ygWYy2pX7z27FO6ju2FzsEVW5sjR1D3yDEf0Ee68xVH7IlNwtLJIm1w5aQiPFq3FsqL7iJSXml5DmA60u8o4ZqktyQvkGI/4L8o1NXtVeAfQOaFvvUefg2BBXcHkb5Er/tBXhH+v4+H11KSf7nqgnyc/QNQnzmrBO1PMdNfjDTluzsR98SraD64oCyYrwVg1CxxG9aE8OxX/qb8nFfifdUx2ocRGW1BPl3egchPiMaJuOslfGNTfGZXEJm5GYpyGILnkClEr9jNl7BPk9qxd1Tqmfhl0re2NOr0T8I8VeQeyXnrJXwtU0B+g2XlcrjVWmfvBZ9S4lxdTyHXZ68bZ9BIaGRh//fSNUEeSD9gxB/I8hTk3XXivjKpgjtxSMljskuSbrznFyWoVuJftECVTHEIzEGctGy1DwOOPJ/f1Itirw2djQ9hBD/KCM2Je+wmfjYthTloG6JT3fCqkDFeC5uKZVNURlPY5uH8t+g1Bz2LpbBna2aJF9GFyHEN/RMl19qMSjhdeq/2IWeJQSwAgZhRyClgsYZdOiohIHY6uFb3zc4tOteIn/jbtUEeQJ9hBD/Isjt3TvtPQ7yEL4stUesisG+Nkf9FX2KldP/6zbh057mSe/DowYzdz/yS/y7CcrVtCh7Gr2EEL8EebQMt22O9Q4uRAwvVR+iMh7HZs+leBcm4QaDUvDnYrhnMeND/IhLDWbN6LvFWvVqWnShlxDilyCvluO25zjqnPEnupcSxop40LPWTwcwHV2KXeb+a9THOA/yjItyEC+UumoikIG3Tf79RaoJ8nx6CSGhiCAXH10cxYMX4gaDZ1yCEVL3yvvxFXrgHMPod1tMLxUykM18w27SWZht+on+yu2RmY1MiC9od8p13foO97gLSlRP/mv32BETXMvyb3gNHUrlF/8liL19KAq6weB7wKGrMVbNsGarV2ZoBD2FED8CFpNlO28cPR2mjS3GbYayFcfVeAJfYKdDGVyF9/EQLjT9CRtjDHb7kMcxxOQidPcEt/8OqHaBGmK/fgZ9hRCvOVrkupXfqobx5NEOi/EsxwDUNE2sa4A7MRRTsdgkKW0/1uAbjEM/tEN1i5/2fDyOX3xJqhtdqh3qXzNjJ2/7VvX2yH3oLIR4vT8+z62j1sB6g7rBAgItsdTx4dfH6Ij0hGWNzkVjNEULtMU1aIoGtopWVkcvfOtLReYdGG56ueNmrLX1jPHqCfKf4gT6CyGeog9066gXAyjEeMMv2enohz1JxF1fRgvEJUa1e2OW1C4fVnWUB6Gayc9RG5MdzIGu3sHeLfQXQjzFeR3kkqPFYQn5A60N/39D2wWIStZem4SurroxZ6MLxuJXny6bHMRHuMn0z0gcvRzmOV+u3h55aawMPYYQ7wIWwr2bdixS4XeU4T5Zx2Mu9qcrMQWP4TrbvTRq4wYMxAf43fZ1brcUYgH6msa/BQRuSKLc6FMqtnS6nD5DiHeCfI97J72vmIxsxB2G/+oqG41RE7EdP+ADvIbB6IEuuANt0RZt0Rld0BPPYAym4UcfcieKsxQDcYHl/DSzWci/JPNUFOSZ9BlCvBPkme6ddEApKZmKcw3zfj9DlMjFaFyVYG4a49Ok9+l5ltki7LFHSNTk+BRx0L2LjjDcy/Y0OJTSMSQiYrwW/Uyum/w9rsMnLnM6uqooyLPpN4R4I8gdZLjo+6YXhhsZBjgOhFyMV6F7qXL2okRB0e5Scp2nqSjIiDei5xDihSBPl+Ggcy1qSDxmsE++1oeabl6xDYNQwXI2GmCotHrKewxLIQU+5jHXghDppP/Peadpo2Hd8SPHIJ58oWUdB1XJwwjDO4l/X5DphfmSMzs6KrlH1q6k9xAiGf1uOe6ZqCfzRjQzKAU/L2RyPNewYtuhUQUPIMeTmnFvKSnI+gLukQmRHbD4WoZzVrfVKeMug+aoM0Ijxptxr+nv3wbvYq+Hb44rKcmiOf2HEJn7Y00UynDNpjavTgwvFU1Ox1uhkOOPTK6k6OiERZ6/vYWaQYsVWcfRhwiRhvawHNe807a0vF/qiEr9NLg/0M7k974dy335CV5Wc4cM0ZU+RIgsymgr5Djm0w7EZaFBDbQ+nvfrSP4Q72VUNLl7518E/DdVBTm3wn/pRoTICVhcKssx33ZYl6J+qSd0SqIenPcsRhOTgkXv+FYj4xCNFJVkbSj9iBApiImy3PJbh/KyCVeWesbl2KCUGO9EP8OazHE8iu2+/zRPqbpHzk+vQk8ixDUV/iv2y3JL51K6y6CxaR38rIwcz8T5hr/pFT4c4Rnxo6qCDP0z+hIh7gMW98tyyaykvr4fxN2lnlTVogezf/xu0vukIob4VODeiAbKSjKviBDiPmDxiyyHbJ6kxBRggEF3kSG+NFgyv+g9xOSqcjv8EeifiSfUFeQVbOtEiLv98aXyHLKHC5mZYFCi52bkBiJ5hfjQ4LjxUEvS8T4f4pXmB2UFWUDrT48ixM3+eJo8d3zFldDMQpVST6yFT30XvO/Q0uTqx4MB/YEo+efiQnUl+UBaZfoUIcnujzNFgTx3/NKl1CxDXcN99w4fxbiDye92OeYrc9A4UOE9spjNyhaEJLs/HiHTGde7lpo/cbVhhYzRPlwYmY9OpuWCRiFPoUS8hSoLMrSO9CtCkqDsaWK3PEesLiW6uh8PmXTh+9yz6O0BTME1pr/XPdio2DWVQpNUPEXG1vT/0bcIcYysChaHRltpgjPFsFu1QBNMk5558QcGWXSIvgQ5Sl7k7q/2HnksfYsQh2QcL9bLdMPHpWYAX2vyljoYhJVS3rEeo9HSoIfJX+NcjFMqUFE8vCLUluQr6F+EOIsfd5brhB9IlZx8jDBtWaSjBV7E4iR3y3uRg2fQ3EKKBbIwRMmaGn9nbtdRW5LXpZ1KDyPENtnHipVynfB3D2qb3Wz5xhrojKGYgTW2rmgvwiQ8jpYon+D3qIrBSqS3hTjTAgLidfoYIbbRb5HrgFU8ulc3C5fYurTdCNejKwZiOIZjOEZjPMbjZTyBHrgdrW0fgtXAkAAKBiXDYtUFGdq19DJC7HG0WC7X/dp4Jj15mIiLfRCQJngb+xEeGqouyRvO/g8djRA78eP2st1vkMcx0w9NKhLLKYrUXaFrH3YZrPweWbxJTyPEzv54qWzn86NJ6XLLFLVkRjraYrLSx3fm/Kq+IEO7hs5GSKL48Y3yXW+zTzJ0ANPwAM5z/fNegJ6Y5uOlbC+4TH1B3qydSX8jxIKs48Rvsh2vnu931X7By7jVcZmdDFyFXngLKxAFhoVgjyw+ZW0LQizQust3u3sDE6Ud+AavYwDuRWtcXOqGXzXUwqXogIcwDO/hBxxAlPjDMpdamdGNPkeICfF/iy3yne51hWRqP7YjF9tDlTGRLM3DIMj7RXX6HSHG8eOBXjjdUpAgGBUGQYb45awT6XmElA5XnCmzvttfo2bgXTRSlT8N+2ErOF6i7xFSCrn1j/8ad1IZA6NdOAS5UL+a3kdIMdKytDwv3G0cdTEw3g2HIEPkajo9kJCi++MvvHG236mLgbHHpHa0gmNe1nH0QUL+kuM23jjaeVTFQLk3LIIMMYReSEgsFovFyv5DrPLGzbpREwPli/AIMvSW9ERCYrGY1t8rJ5tITQyUPJwbGkHWdomK9EWS8sTTxB6vnGwNNTFg+oVojywWl/0H/ZGkevx4ilcOVp96GDg/hEmQoY2kP5LUDldc6Z179aAeKkDjUEmyfhN9kqQsmSeL1d451xSqoQIMDZUgi91plemXJFX3x0M93OvgT6qhAqxBPFySvDTzZHomSUH02iLfO8dqSi1UhLbhEmSIt+ibJPU4RnzvpVsNoRIqwpSwCTL0W+meJNXCFQ9761SLqYSKsA/VwibJ+7Sa9FCSQsQriH1eulRtlt1UiIdDt0fWVohT6KUkVThKzPbWoXpSBRViUegEWUBMjx1NRyUpgejptTvNoAoqxeVhlOS+9FSSCtHjSt6GKwQqYg81UClGhlGQC7Vr6a0k6hwj5nntSh2pgIqxBRlhlOSdWiU6LIl2uKKv9470BhVQOW4LoyBDLMn4F32WRDdcUUMc9N6N1lL/lGNGOAUZYnKsDP2WRHN3fIL4yXsXupLqpyB5qB1SSda603NJNAV5lB8ONJjqpySPh3WPnK83pu+SyKE/4I8DLaL2KcmKsAoyxBYh6L8kWnLc2MtSQn+PC3hHT1muCa8kL2Q3ERIlOc4U2/xxncepe8oyPryCDDGGXkwiQsa/xM9+Oc4P1D1l2YVKIZZk1oAj0eBoMc0vp7mQAQul6RbmPfJ+cR6dmYQ/XDHYP6dhwEJt5oRZkCE2pJejP5Nwy/GNfroMAxZqU4gG4ZbkhWf8kz5NQktattjrn7swYKE+z4dbkKG/w5t7JKRoZ4q1fjrLE9Q75dmA9JBLsuhNzyYhRJwg5vrrKgxYhIEbwy7IhaINvZuET5BH+eso9RiwCAUfh12QIfbGz6V/k3DJ8YN+uwkDFuEgD3XCL8nryp5NHyfhkePL/LkozT7TYeTZ8AsytPm8TE1Cgn8Xpf8eDRiw4MGev5I8lp5OQkDWSf5dlP57DKHOhYhbIyDIAuJBejtRnTLapACyQ7GKKhciZkVDkAv0q+nwhId5pUZLalyoCP2NvSNtUNOy6PNEWbSLtbwgHONNalzIGB4NQYZYLk6h3xMlSS8nNgXhFOWRS4ULGbmoEBVJ/iB2FH2fKEfG8WJeMC7RmfoWQu6JiiBDf5TeT9QLV4wMyiFmUN1CyLeREWRRoF1J/ydK4W+ZzaKjBg5S3UJJ4+hIcm65dGoAUWd3XFPsC8oZelPZQsro6AgyxPdnnUgdIEqQebJYGpwrLKKyhZSdqBwlSX6TSkBUoIz+TnBu0JBXpkNMjygJMvS7KQYkcES3IJ1gKFUtxPwQKUEWB/X61AMS7GFebXEgOBeIYy1VLdQ0jZYkb2RZThIgaaeKlUE6wM1UtJAzIVqCDPFN1nHUBRJQ9Fi8F6z5f0xFCzl7cU7EJFkbSmEgwUSPewZr+rWQR0ULPX2itkeGfiO1gfgfPa4fTCGhv8fjVLMIsDxygix2a5WoD8RXMk4X64I2/BVUs0hwQ/QkeTEbPBF/o8fvB230ralkEWFG9AQZ4mWKBPEN7b7gTf5dKllEKMBFEZRkrS11gvhCWnaQuceHRlXspZJFhteiKMi74hWoFcRzsk4Sy4I390epYhFiN6pGUJL1BRnHUy+I19kV41Qw9h+pYpGiXxTjyBDPUS+It3J8iwqGfjkVLGKsRnoUBblQNKdmEM+IV9B2qWDoY6lgkeOWaO6Rc4WgbhBPECeIRSoYeWXson5Fjq+jKcgQc7OPpXYQL8IVw9QwcR7oRZMroirJT1A7iPz98eWiUA0DX0rtiiTuK79dgv5orWATVL0x9YNIJeN0sUEN825F5Yoo+1DDlWWciwMADuJO9ST5z3JnUUOIPMqID1Qx7g+oXJFlsCvLqH34Kfl4WD1JnhU7mjJCJKHdqYph18QB6lZk2Yjyrqxj4ZEnDVdPkntRR4gcOa4k9qhi1oOpWpHmXlfW0anIk15W7Sp1nl6bWkJck32smKeKUaezh17EWezSQiYXedYrqu2Rl5x1IvWEuN0fP6WOSd9KxYo817osOrWqyLNGqFbd4kXqCXGFXk/kq2PQs6lXkWeqSxtpgFx1d8mFWhNqCkmatFPFanXMuSEKqVeRJw91XNrJ9cUOfhU73ttQ4b/UFZIk4k2VjPkVqlVK8JJrS7mlWPvbQWpJ8nvUFZJc9LiFSoZcGdupVSnBNmS5tpbORSS5EL3UyrfoRG0hjsk4XWxUyYwfolKlDI9JsJe7ikhyPu5SSZJ36Br1hTg9zntHqfNpLKdOpQwbXF4QKS3JB9FeJUmeGStDhSFOosft1UoYupEqlVI8IMVqigYu9qK5SmGLLtQYYpuyZ4tctQR5JjUqpfgNcemSvAl11bHo3ekZ1BlijzJimhyzq415uF/CcxqggBqVYtwuSfruLZIsuQzV1AnC5bDcELEXrugsy+g+hNvqBIfGaOpTyrFImvQ9UeSpc1FBnV1yV2oNSZzspoudcgyuHQDgMtfPqcKWTSnJddKkb0yRp74LXRVB3pdWmXpDrDlKzJZjbuXxG4BVEp7Uj9qUknwhTfri+KTIc59UZ4/8dewoSg6xClfcK8vYngEAPC8h4e13alOK0kSa9FXEd0eeWoCO6kSS76bmEFN0Tdslx9DqYx8A4FLXT+pIXUpZ3pMofdnYcOS5O3GxMtkWaXHqDjHbH0+Xm6b2rYQn5VCXUpZ8NJAofs2KFB36XZ18i4+pO8T4OK+jLCO77bDZd3b9pMas8JbSjJEqfr2KPPlzSZnOEsIW7ag9pPTu+P9kXQapjHUAgHVId/2st6lJKc0+ZEsVv6L29IIqe+Qt6f+j/pCSgvyuLAMbftjgn3D9pFrYT01KcYZKFb9M/FDkcE+Z+hbjqT+k+HFea1nGdTEOAgD2orrrZw2lHqU82yUU4yw66hbpKJLruhi+tNGMGkSOcPZ/5JXa/PKwsb8mIfSxjXpEMFCy+HUsci6xABlqCPLqrJOoQ+Sv47w3ZB/nHZSw9+hNLSKQVYyz6Bhb5OmqdN3TB1OHyCE5vkJehG71YTOf4PpZ6cX6B5NU5iHJ4lcJK448uxC3qVGQM09UpxaR2Bn/FH/IMqpnj+SPNpRQOJEQHM7Xkb1HbnL4pAMAduACXqQmyhznDZZlUOdjz2ETf1/C076jDpEj9JAuf8VrwKmRk8xueylPvKo4KMucph35Eui+BkFLahApwlrpe+Q4vvbw4DDJsTXjdGpSKnOUmCPLmNoeMe7pEp72CTWIeLxHPh87jjz9AK5UQ5Jfoyil8nFeF1mGlI6lR/bHV0goTZRPBSIe75EFehZ5/gpUUkGQC0VD6lKqyvGZYpssQ+p/xLA/kpyWRMghHvSgl/ncIs8fo0Yc+cfYMdSmlERMkFfacOdhoy5AY9dPq4G9VB9SilUSaqOUvle6v0gC3A1qhC3uoTalohxfJs+E3jxi1DIq2D5L7SE+xZEFBhd5/hrJ17STHLk82ks5yv5D/CrLgBodabWej0tcP60CNlF5iCEbUFG6/KXjZ+XCFuJlKlSq7Y8fl2c+s46Y8zuSD1oIKU5/D+SvWZEj5AK0UUGQC+K1qFEpRFplcUCW8dxwxJjzcZGEY5blVB1iSq4nQYWiXalXo7IKkvwlVSqV9sfT5X3hW3rElCdIeB476BFrBnsgf1WKhcleVaPYUGvqVIqgt/KiKc5+nC/hed9QcYglOyXU2S49ehR5QwGaq5D+tuaMf1KrUuM4b6Uso6mMP4+Y8UgJz2tKvSEJGeaB/MWxuMgbFnuQYJfE6Eu1SgG0/vJM5u+OHrul9D57n2pDErLPkz4f1xV7x6MqCPKesmdTryJOPE3skWUwdYpc4HhGyvPyqDbEBt4kp00v8oZdqK2CJI+iYkX9OO89eeYy+Yj5bpFy9v0KlYbY4iDqeyB/DYvUSAamKJH+ptWgZkV5f9xIZonvgiPG21fC887BbioNsclkTwSw+JZAiYvU06hakSX7WLFEnqn8XU12LSpIeN7TVBliGxk1U0qPakU6UgMrlGiAql9K5Ypqutv98sykbRHDvV9KN77NVBnigE89kb8+xd7RV4U98iI2doqmHJ8htsszk4VHjPY3KSlCj1BhiEOu9UD+KmBDkTdsRw0V9sjtqF5RPM57XZ6J3FLEaO+Qct+PHaaJU+Z4In+9i71DiVt7q8QJ1K+oZR/XFAXykuiXHDHYH6FLeOKdVBeSBG093yMflNA/XcIe+X4qWNQCFp/JM497ixjszVKeuJjaQpJgvg975Okq7JG3ZPyLGhalcEUzmfVjfztirD9I2R+3pbKQJLnB8z2yN/twx3vkR6li0eEY8bM3ZVjkmOpX1BWSJPN82CMvlrLtcDm2lz2NQhaV+PGdMncP644Y6lxJF0wIUXuPfIcCe2RtAJUsEmSeLDbKM4t+0l1hKjWFKB5HXoZ48IK8K/1/VLMoxI8HyTOKykWubyyU8sT6RdrnEKLKHjmzSGFZAOiqwh75KapZ6MkoK6+6W/HrzZ2kPPEN6glRco88uNg7VqlQIXkvy3GGf3/8pjyDqIrtRwx0iZSDjmzso54QJffINYoUlwWAHiqkvz1PRQs18VqiUJ45PFPEPO+WXOCeENX2yGOLvWOdlBJaLse+jLJUtTDvj2fJM4asIpWwVkr5AlcZ26glRAqtPamPXFDsHY+osEceQlULb7rbFTJN4YkiptlLyhP7U0eIJD73RP5mFnvHHyrEkfdknE5lCydlxLfyDKESthwxzG2oJOGJGUUymglxy5UeyF/HEu+4V4Vci/6UtnDuj1vINIMBRcxyqJQn3kcNIRLxoodIHKuLvWOJEnf24v+muoWPo8QP3txcypPS81fHMmoIkUge6nogf4NKvKWjCnHkHpS30KHfKNMEeknfiXSkghDJvOZJ8tuBYu+Yp4Igbyz7DypcqMg+Vvwq84vbyiIm2VTKM7+lfhDJ7PWkv8dHJd7SUoU48p3UuHClu90uc/nvKGKOcgoKXU31IB7wrAfi16HEOz5TYY+8Ous4qlx45PgEbY3M5f+uiDl29mTXQYgMclFZuvill6j8VqhEDxHRnjoXHkHuJnPp2xQxxs1SGqPXQx61g3hCbw/E7+US7xipQtDix1gZKl0oOOOfMsttFk+OHy7lia9TN4hHrPbg8kajEu/YhooqSPJF1Lpw5B8/LHPZL0VhkS9rDSQ8sTr2UDeIZ9zjgfj9XOIdD6oQtHifWhcCMv4lcmUu+1tFzPArD8oaEiKX7z0QvydLvONnFQS5ID2Deqd+/LinzEU/p9huVsaBXgVsomYQT2kmXfzqFfmeeIhrWYyT2MmvEOu9uqck50CvJ/WCeMy7HojfDyXeMUUFQd7JS9SqC3JXuQk/Rcv/vCzlwvQK6gXxmAPIli5+A0u94xwVDva6U/MUJus48YfM5e5SzAQvk/DEW6gWxAcGS5e++qXe8bAKe+RVsWOoe8qi3yZ3uecXMb8lUp44j1pBfGCjlPBa8bG8xDu+U0GQoV1L3VOVo7UVMpf6ymLmN0jCE5tRKYhPdJEufcNLveMiBQRZ/4zCp2r8uL3cpR5XxPQKcaGEJ06jThCf+Fa69LUs9Y6hKuyRC+PlqX0qcpT4SeZCV8YuyeZdH/nUCeIbl0uvabG1xBvWIa6CJA+i+KkYP24td5mLp6fJ6KE3hhpBfOQt6dL3fql3XK9CFHlzxvHUP9UoI77zLu/yIKrzwjQJGXslWG3x8WCpd0xS4mBPb0UBVIz4VXKXuEkxs5NRAZYXponfDJQsfHVLvWG7B9kcSeyRZ1ABVTvQm+XdgZ6MUirleWGa+M5q6THelaXe0U6Jgz1WtVAKrYbcBa5U7ECvALUkXzEhxB86SJa+N0q94Q0lghbicaqgSoI8Vu7ydi1mcgskPDGH2kACYJpk4bu71Bs2qZFpsTH7WOqgKnJ8pjggd3m/KmZyT0qolVVAbSABkIdzPY4iK1L3Ddo1VEJVEt4Gyl3a80rkC1/q+okvUhlIQDwuWfg2lHrDCDWCFu9SCZXgrBPFFrlLO6iYua2SkFC/kbpAAuJ36FK9Y5rB0aESgnzg7P9QDVXIr7hD9tIuK2Zuo1w/7zaqAgmQVp6W4QSAxmpkI99GNVThQsgvcpe1aQljc38X6XNqAgkQueXqWxq8ob8ae+TZlMPgD/SayF7WUcVMbY/rxPcLWMGCBMpeZEn0jyqlmjkBM9UQ5EJNpyIGfaD3meSvPVhfzNS+dP3EIVQEEjAPSPWR1aWev1uJ+3oC2sNUxEBJryIK5S5pixKm9pTL58WLNYEiJAjmSPWR6QZvaKnGHnkJNTHYgMVIbwMW7nMsO1INSOAUop5EHzH6zjdEDUGGqE5VDIzMk8VO2QGLdZIjyJ9SDYgCyOyxd4fB8+crIsjaAOpicAlvnWUv5zUlzGy2y+fVQB61gCjASonZyI0Nnp+HKmpI8jLqYnCC/J3s5RxZwsyedvm8h6gERBGukVh6q9Dg+R0U2SOnZVEZg8mvqC1/MVdLPqqYSx0gijDW0+vTCkWRe1Mbg9kfj5K9lCW/iu1FeZc1MVhSiKhCLtKlecq3Bs//QhVB/oHaGADxf4vdspfyiRIm5rax6QCqAFGIG6V5ytuGgq8rIsl6JvXR/4S3LvIXsmSA4XWJXfkICZq3pXnKM4bPb6DKHrkX9dH/gMVC2ctYtVRGhLv7TQ0Mjz4ICYodqOBJR/a/uFcVQZ5DffRbjuvIX8a7ShnYVR7sIggJjk6SfKWT4dNHqSLIBen/o0b6K8ivyV/Gd0qYV57L/cQy+j9RjCkeVUQ8xAJVBBlaW2qkvwd6e6QfBGBLCfNa6up5l9H7iXLsRkUp3lLHJCSiiiCLN6mSfmYg3yp/CUvfPprs6nnD6P1EQTpL8ZYMk/OR81QR5K2xo6mT/gUsZslfwj6ljOsxV/vt1fR9EuGgxV7Dp9+gTtDiAuqkT6SXEwXyF7B0p7C2Lp7WnJ5PlGSHy8tOf43Nhk/vrY4gs8iQb/vjBz1IJcfWUsaVzS7TJILcJMVjVhk+e4w6UeSFVEq/BHmxHxHkXcywIJFknBSPWWL47K/VEeTCCv+lVvpAWmUvlq93KdP6ycXT6tLribL8ibgEj5lv8myhTtCiBdXSj/3xIC8W76NSpvWRVHknRB1aSPCYHJNnV1RHkIdSLb2njFjpxeKVLic4zMXTvqTPE4UZKcFjvjZ5dgN19sg/US69z0Cu78XS1TIwrIeTflplHKDPE4VZ6eEOuY1CUWT9DCqm1wGLEV4snVEj0uRv/d9OjyeK09CzHfK9CkWR9dZUTE/JOk5s8WLhjLroNpVaK5YQlejnmSA/rpAgi+HUTG8DFld7s3AzDQwr2UugcWyivxPFme3aZ+aYPPk1lQR5CTXTU7Sx3ixc6VtH+Um3u2lGbyfKsx+VXfrMQpMnT1NJkJmL7ClHexOwuMDArHKTftoL9HYSAtxWRl5u8tz5KgkytCspm97tjy/2ZtE6ST2H/om+TkLAGy69Zr3Jc5cqJciiL3XTuwyL571ZtMcNzGpR0nVi2baJhIG1Lr1mp8lz16glyB9TN70T5N+9WbQJEg89utPTSUi41FUxrnyTp+aqJchbY2WonN7IcXWvFm2egVl9mOSz3qWfk5DgJvWtiulTD6glyIiXp3Z6I8h9vFqyrQZmNUnaFWxC1ORTFz7TyOK55dU61mN3PY8EeaE3C3aOoVGNl26mhKjFzqRTOwXaWjy3ulqC/AK10wPiaaLQmwW7xtCokiu0zSpvJEw0T9prulk89UKlBFnPoXp6sT++x6sFMz6GeyWpZ02nj5MQ8VTSXvOkxVMbqBVF3s5jPS8EeaZXC/a0oVENT+rS9Db6OAkROUl7zZjQ7JAF0stRPyWTdZI44NVyGZvWCCltoAhRmf3ITNJrPrd46vmKCbLWhAoq+47eFd4t18eGRvVqEk96hB5OQsZ1SXrNGotnnqeYIIseVFDJ6IO9W64F0g713qN/k5DxfFI+UwkFFs88V7Ud8htUUNkR5O+9Wy7jv/XJ3PRfT/8mKRFFbmr5zJqq7ZAXUUGlcvZ/RIF3y7XP0KjedvycC+ndJHTsSSoXuavlM2uoJsj7Y8dQRWUGLFp6t1jVTIxqmmQjJURNrkrCa4ZZPjFLNUGGnkkVlRmwGO7dUjWQ9lVuDH2bhJA+EhucAkAedOUEWbuCKipTkJd7t1SXmZjVYsdPWkzfJiHkgyTy7XdZPG+zcnIsoN1JFZVGejkvl6qZiVk5LVCfiYP0bRJCNjj2mcstn7dcQUHWB1NH5e2PO3i5VG1MzGqbw+dcS88mIcXpRY6elk+br6Agi8nUUXmXQt7wcqnamxpWRUfPGUC/JiHlLoc+M9HyaZ+qKMhMfJO4Q17t5VLdbmpYzkqkfEC/JiFllEOfWWn5tEkqCvJO6qis/fGZ3i6VebKas0ulq+jXJKTMc2Tp9RI8baSKgoyM06mlcvbHzbxdqAdNDaurg6dkWV4lJURldiMuseb3ACUFWa9NLZVzKWSgtwtl3pT0aQdPaUWvJiHmEge2PjPBs25RUpBFM2qpnJDFDG8X6i5Tw5rs4Cl96dMkxNxr29IrYE+CZ12q5g75NmqpDMqIbd4u1K2mhrVY2rkzIWpjvz/OjQmeVJB0hWWPBflRiqmMCHJFrxeqvalp7XFwBfQX+jQJMd/YtvTxCZ60Xs2ABfQXqaYyIsg3er1Q11kYl92E+Qze0iOhZqfNzUcGcqVJu8+C/A7VVEYE+QWvF8rqht3NNp9xKT2ahJyGtiy9Y8LnTFBUkLWvqKYyQhZzvV6oJhbG9ZzNZ3ShP5OQswQ5yEEOZmEyRuIxdEUrg7rGiXviPKGoIIvlVFPXZB0n9nm9UFZl5T+3+Yzn6M8kkmzBHLyB+3ExBAQqJ8ywANqqKsg7qKeuScv2fqEqoNDUuLbafMaH9FwScXLxGaYk/FeFqKaqIBfGjqaiug1YdPBjqayOKerZesJy+ishAH5VVY4hkHkyFdXtkd7TfizUEgsD68YcC0JsM0VhQdbOpKK63SF/7MdCfWFhYO/a+PzF9ENCACTXDsqvES9PRXUryKv9WKgJFga20UZ+Zkf6ISEAgGtU3iHXoKK6IuNfotCPhXrB0sQS38zvRz8kBECew6YOPu+QL6SmurulV9ufhephaWT92G2aEFvkYwquUneHzM7TLo/0bvBnoZpZGllOws/PoicScoT56IJ0FS9Pt6SmutshP+rPQlVEvuVf/Wz2CiHEEavQD5VVE+R21FR3R3pj/Fqq3yyNq4flZ9ORR/8jpBTbMBTVVRLkG6mp7gT5a7+W6iNLw/rS8rMX0PMIMWEPhuMcCnJEBHmjX0s1OMHZsdXf+Zb0OhKZPe0vWIzF+B45WIQ1NipX2GEnhihxoVq/iZrqRo5P8CfpTUCgUwKT6p1U12pCwrCH/QrPoTOuMhTNCqiDVngIo5GDDS7esgPPoQoFOczEy/u3VOcnMKefLT77FH2ahJJ9mIyOjhou1UJnvIbFlofg5mxFX5SnIIc26e1iPxdrbQJjamr6yXH0bBI6tmKQizBCFm7C61iTxHv/wD0OGqNJHu2pqm6S3m7yc7HeTWBIb5p+8nN6NwkVBzBUUkraZXgaC1Hg8P0/oh0FOYQ75If8XKwHExjRLlMT/pkeTkLET7hEsu/UwUDLiolGfI6LKMgh2yEP83Ox6iY0of4mn9xEHyehYQIqeORBl2OEo2O/g3gZWf7GkFtRVd3skCf5+/dzWQIDWocMo4IlSR5wEOI/g70u34P2+MyBR2xENx8jyqxl4S7tbZa/gvxSQvPpavCpbHo5CQnP+ORJF+IlbLX9U823UU9R0g65HlXVjSD/5K8gJ77gscTgr/nl9HMSCsb56k0V0BU/2D5kfNaXdDitJlXVjSD/6XO1VGxMaDodS32qHT2dhID5hgE3r8f1+NLmz7cMzb338ApU1eQpo+X5bT6jE5rNL4jznh4JHbttNuv1YjTBB7aiyvl41dElFeej3FmU1aTJ+Jf/ptPChtmUjCP3obcT5ekd8KXl+phgqybiMjT2cof8b+pq0pQ9O4CrlTYqG68pkTb0LL2dKM4yJcrF17MlyvvR27O8i9jR1NXks5AzgzCap22Yd/GWTqPo70RxOilTkdieKM9EDS/evoOq6qa0UK0gDOY8G+aSW8xc3qG/E8X3x7oygiwg0BDTUJjgZ16LK+W/eSlV1U2ORcNgzOVTGyb+dpF/P4MeT5Smh4Ld7a7BvAQ/9R50kf3WWVRVN/f0mgRjKtfbMPFCtDzy7+fR44nC7FGus91f4xb8nsDLhpbKaXI13qaquhHka4IylJ9sfQ38K6vzF/o8UZh3FJXjQ5dHnkrQk+QDmdnTz1FV3RzqtQrKTLrZMvRBh//1Svo8UZhbFRbkQx0ppyU44Kso6109qapuYsjXB2UiGbYKb+8/nDG5kT5PlGUfKikuyAICHSyrxM2V1fqJxTdd7ZDbBWcgPWwZ+y+oAIEd9HqiLF+HQI4FBKpigkXmxfdy4uCXUVXd7JDbB2ceGVhty9xHQuAgvZ4oy5CQCLKAQHuLffKXEmLJ+jlUVTeC3CFI47jflrkX4Eb6PFGYm0IkyAI1MMv0N5nsNpu6MOskqmpIQxYCcZuNmbbQ54nC1A6VIAvoeMr0atZL7p69jprqbofcJljTuIHeTEJObsjk+NC4DtsMf5tCd1fAeS3EZR7ytUEbxmf0aBJq5oVSkAUuNinylYs6yRenf4Wa6i5k0TT4Qih76dMkxLwdUkEWqInvDH+jucnXrXuQmuouZHFZ8GYxiD5NQsyToRVkgUr4xvB3Srays3YNNdUV8QuDN4p0m0d7hKhI5xALskBlfGvwO21PsjRnWhY11V3IopoKRtHUVp8DQtRjAxqEWpAFqhrWlRmdzLMKyv6DmuouZCHUMIpn6NkkZOThU3RUokuI+0oXWw1+u/rOAxYrqKguKXuaGiaRju/p4SQ07MfrLnIRVEyCK/0ddaTz50ygorrlGFVMogF20s9JCNiH13BehMT40Bhc6vfc5rwCHHMsJAQtdqhiEp0TtpwhJGimoW7kxFhAoDyWlfpdH3B687YR9dS9IC9XxyjYypSozO+4IZJifGi0QEGJ33emwzoWZU+jnrq/q/eVOiaRgfn0eqIkhRgTiqrHMjtd7nZW/e13qqkMQZ6k1t2h1fR9ohxbcWPExfjQHrkkrZzkWEyimsoQ5KFqGUVj7KL/E6X4AeengBwLCCwo8ZsPdvLpXlRTGVdDHlGv1QyviRB1mIIKKSLHAn1L/O6O6nSwV4gUQb5RPbPoWup4gZBgGI14ysixQN0Sv7395lRaXsa/qKYRqWZRegygEhAFeCKFxPjQ+LXY77/a/ifnUkulUO4sNQ1jKNWABMyglJNjgY+LzYCD4vtPUEvlUEbsUdM0hlERSIA8Y8NGr8W0iAnySyWySxhB9v9qyM/OlqwCzsOlaIm2uA5N0RCZnhnHi1QFEhDjE1rneZiMQhRK6NSs0nik2Cxsth1BzjyZSion7a2G2GZv0uujL97BUoMciE1YgHF4CI3d9qwtNV6gMpAA+DJBFTcdfbDn8L+tHSlB7llsHjbY/dwcKqkcOa4ptti5rjEIi20Z8mZMwa1S98z9mHFBfGYVqibYG+cU+ddXRkqQexSbiUU2P6UPpJbKyLCoJbYmmuo6eM1x17tdeAOXSzORe3GQGkF8Yx+usLTH1thU7N/fHClB7l3sd3vfriBfSjWVkfCWoNJbJp7HgaQNew7aSjKSm3h7j/hGT0tbfKBUyK5vpAR5ZLHfbai9T+0960TqqVs5rpoodnwdfndt3N+hpaQL1axxQfzgM0s7fMqgROyYSAnytGK/W3d7n3qfeuqSjLLaGsvKpnhOUuy2ENOkVAKoyUpwxHO2WR7RPWf4mVmREuTiVZHttXHSOlFRXVH2NLHEaoJrYJZUM9+NvhJ6j1XABCoG8RSrHeETJp9ZEyE5rlnsG8A6e58qEP9HTXWTd3yCnmN9n/1XD0x9oZTuvN2OJBsRIpv5Fmmbd5r2sylEjcgI8p3FfrN3mfLmiyCPsprey7HRI3Pfgc4STOZyrKRyEA/IQ2NTq2uG/RafbBsZQW6NQUVGM3bS80GOu1lNblPs8NDkC/GChKsjVTCF6kGkY344VznB8XbqlSAqlvKWSVVNmrRLtDzzqb0CuZ6b/UxUkdIQdRsVhEhkD2qZWtukBJ+dlsJyrK2gqiZ/L0+3upfX2Ac5BoCfcYEEQzgfc6giRBrPW/zxT0RuStVMLjGGU1eTJPtY8Y2VwG3wzfg3J7gLZfOrEnphN5WESGA3qplek95u4/NXpHLIIkdvFTuG+uo8evy8VVz2F18dYIfdA4OEFbdmUE2Ia0aZWtg7tj4/IKWjyAJilX4bRdnZzbyrRKHZdGYUK5biDztxjSRjuM/WHoYQM/JQz8S2rrJ5PerzVBdkCIhleqtYGSqtvd2xELnmU/l2IG6wE9dKMoVamExVIUkz1dSy7G5UDkg5qo7AEd9X8QpUWzvR4znmk/hogJG7FtJMoSPWUVlIUjQ3sanbHTzjbsrxobFP9IgdTc213h8/a9WEJsjilttwiTRTqIThyKe6EIfMMz00Xu7gKR9Siv8e38TTqLrmyW5NzKPH55Wo7eo/q3GuRFNoUaI4CiGJuNfElto7esoeVKYQ/z22xBtReQ3RNfMi9PEADvNK86NUU87AIBc1nEmqYS6ksx0+6YFQS2gGzkEd1EcTND0yLkZ9nJtkjrWWJ7pSfR1Gj4co4hRfSKgFV3Q04KURYpPJptekCh0+aX4ohfhVbE1QLiEff+JnTMcL6IwGzkofvMxocsno8ZPm03W9QhHX8ZLNLI6H2WWE2OAmEwtKptRro9DJ8VDHv+NWTEYXZNndJ0/KOJ4q/LccXy4KzCufblTKMXpKN7a6+IZ6QyzZYvLd7BzL6m5mjA6ZHD+W9LztxVsWtfGKjfd4YeQw5c4Sm8yvHX+mmGscwNXyL3WiH+PJxIJRtnov249HVw+RHA90HJQpTiG+sld49HVeF4nFYrGj9M/MJ+lJBZ1jnSeFvi/z+VI4CRNmF/iTPYMYHBo5HiRpBmfiwsRv6005jol+wqLcdp6S7pEj+XDvr/PjIcxPJobx0LhJMmiy/SS3oGIYygGV6C3tjr0YjPLWbywUzVNdjhuIfLPpqY61yrrIUI9M8Fqsov6QEkw2/TKfPE8qL8cVPGjwsBh1rd+6XYhUvgpyplhv/tdR5fpoBbjKIzPMwngqEClGVxNbWezimTsV77BXA996Mpe5aGf95tkpmwKXfayY7cXJqj9846Ex3ootVCFy5I9/tkllcG8OClUYl3r4TTEfj1u/vVuqhitGmE/K1YFWrrBHBw8NMluJu4lEBRZLzbD4m4PK5iPf5XnP9tFW9/r2pGTYQtxuviDVsDoEjrLCk6O9v0Y6hiR9ZEOihNl5xTTXT16oYEundAz3ZVbHWl4TSb3o8cXigHn0+JOQuMqDHhtnB5+6BxKVaW0iXDL6rj+imBzXxXzf5vUxi58jrW5qyXENsdN8MvqHxlU2el45q46PBkpUJA+VTOoFymCXnexc30Y37PR1ZptbHe2lDhlltTXhjh7/zWAfvsIxdJHK/GBiFy9Ie34FJcS4qgdJbolYZ3FjMWX2yOkZYrlVssuaULnLLtT0wVg7YhuVKUUxqzsh75vTGAXk+LaAKtZMsaptkRJHeXW0zVa7wa9D5zBjfIqtfU9tSknuMbSH8kkVFTKjW6BiXFvC8WSyFJr3yyzUKkVfjtuLfVZLMyaUMb6GPt1bmkh1SkGMb5Y1l/qOg4kuS3g24nhIyuFk8nxvWjlZGxlpMT77P9ok68W5L6QuM8038+2laG0P4hV/mlhCP8nv2Y2mAchxa/yowBx3NW2DWva06O6Nm5lfkj40rgttAcpCiT2pEyfC7aRKpRCfmNjBVOlv2oIrfRXjC/GRInP8m3k29h3RTHKrKT5PtDyNsT3EbrPQWcMYV6MhfqVOpQzPmljBOg/etROtfLLhbLwqNQbullvMbkTkRG9nXFEba94N5O9s23Uhd5w7fNxbnMNr1SnD7SZlN71hH271oWjQS55fjHbKt6YHe+XSI3X9QxtrXlyzqMAsC73j/I6MCF4vJUHT0CQN0rvw2zAPCwLUxouKdpC8Otol68v+Q79JfG3368tPkXCd3j4fiPTkAV/k2Wsijt720ZmHOh7Y6xV4R+ErX6bNi5eEP0hRXTwvcu0u0wX4LSLOs8V2h1tZoy12U7MijVmdtykev3cn+kncJ2fiLuXvF+xAplliXvnQSnG5s8S94jsnS3Ul1kfIfYb6njZ0NbZStSLMRJN196P74lJcL8FCm2JMSI7ru0SpOrI4Rb9Jm6rlOVus+7EvYl8w6/guyQ3Y8inCDDDpvehXguh36Jxkgc44mmEYlodormea/S4zwyXFJ+hNxUTzUpoqlRLxngkBJNefh6VUrohyk0k3DT9ZhSG4wpE93onx+DN0c52Hqsa/0UFxSkgaMOlNxZtidzIicn2kQhV/k4/LApDkah51HyNB08Ckn4b//IHR6I7LTXKJ4qiLtuiNyaFoLGHGPWbZyC2VF+O0ymKQ2JhsHuLYCJeT/Dyg/rwfUb0iR56J/D0b4M90AEvxNT7BRIzCOEzBdORgmVKXPJLnA7OaFkMVluIz/inucHZwVzz61SvyPTDaBtT4ZgIVLGKsMlnrdzk1nrAT5Y1nfLGqFz3OFH3FluTrOt0RmRQ3KxYH1KdMD2WtPGLOl55XQia2NlOFFf6rnhhXEm85zaIoujPuHqoTV3d0DaiUISU5Wpi14dzMqfGIF818q7lSYqxrYkTyYlwNfbE2pZZ1TWBNcXSMpVdFBuMmnJVRyKnxiO/MPOs5ZcS4wn/Fy+Jg8mnh45UrJOIHAwPrvkBJjg7GNcgu58R4Rp7ZbduFquyNW4lNyXZLHpjC+bHbLZonei/J4+lZkeByw/W9nRPjIe2NvSpfgVzktLiYnlz32PuRk/J9kkcG2KOMu+RocI7h6g7kxHjIy2apb02CvoF3s9jrVAgqohMmYy9XFcBBk6R+vyT5HS5ByNlrsravcWo8ZJGZID8VoBhnHK+NdHoxoRMms/ZYMd4LtJNvOj7lEoSa301WdhqnxkPyUc143r8NTI7Ty4m5Thz/RrzDPm8GFAbSNvLvUQnfcRFCzNcm67qQU+MpHY13yHlZJwUTqjhP22zX5S/BEKzhCpoyN1BBFqiREhdxosq7Jqu6gVPjKWanP2mXBHH94yKx096+uBP7uiX919a/UR+buAghZZiJ57FPjLf8YOZNfXyX43gjsc9OB7xnQ1hcLxiWedifzG4m+B4uQyjpbZJOSrwlD5WMgxYz/M45rif2JHLvLAzCDq6ZA3oELMgCN3FPFUqM+00348R4ThtjQd4VO8bP2HHFRH3wMvCEoh1jVWYjKgcuyX25DCHkWsO1vI0T4zlPmZVHq+XnBelfrZ26JZZxpZLimcAFWWASlyF0GOexP8yJ8ZzPAu+ud5T4xMqdy+N1FjRJmt2oFbggZ2IxFyJkGFdVeI4T4zm50I2vW73jV7iil3VVCuazumOsAnvkupFvDBAt9pmsIy/F+8HFxrO/KVbGj1S3mlalNdvQkV2TZ7bAvo62yOdShIa1vKcXIA+YlSTI9F6Pj7FqyNSaSVNS+EQBQRZ4igsRGsyyYdnO1g/eMvOhzt6HK3pSjv2gpQKCrONzLkRIMGuWy7uXfrDMzIfe9bpuxf/EDjP3vQb7uDLS+M7koMDfUZsBqJAwyWQFt3FqfKDArJ75ttjR3saPXzGvg8AqFXLprETYguXNw8EIk7sAzHbyh9uCyEXWKol8sw7Rs7kmkvnDrMm4z+N9LkUIeMrkGw7xh1FmdZEf9lKQ3zBz2he4Ih7QRwlBrob1XArlechw7RpzYnziFzP/meuZHJdLN9sfN8QBrogH5KKqEpLcjl98ledOw5VrxYnxiULUMPaeAvF/Xu2PnzZz2FlcD494UQlBFnibS6E47QzXrRMnxjfMzny0Tp7IcdZx4k/jF3bmWnjGPlyghCBns2af4lxluG73c2J8Y6KZ97zvTf5xM7Oabsyu8JJJiuyRH+NSKE09rlrAbEHc2Hf2p53qhSCPMXbUrlwJTylAEyUEOZ3V+5TG+LRhKCfGR5qbXbC6xYsL01uMX7aI6+AxsxTZI3fgUihLvsk1IpYW8pMXzHxnlvxmTbWMX9WCq+ADbRWR5JlcCkXZzhxyBVhi5jkF8TTZAYtuxq8axVXwgV/MolM+j0tQwMVQErNab6xF4i+Xm/nO47JT3iYZv4hxRX/opsgemcUcw7U3m8+p8ZURZp6z9awT5e6Qlxu95lxeGPCJDSadbf0eV3MplGS+yXot4dT4ykbzrvEyC3GedaIoMHrJPVwB33hCkT1yDpdCQcyKb67l1PiM6XnPMok9qPVzWMEiaHaYXc30/Ro1UY8PWHxTET409x15e2S9qfErPuD8+8goRfbIbH+qHuNN1iqPU+Mz+SbdvwXEpvi/ZUWQ7zB+xY+cfx85gDpKCPJ9XArlGGm4UpU5MQEwxtRztKdkCXIP4xewm4S/vKGEIFfGbi6FYjzLasjKsBc1zQQ5T68nJ+mtP78QqUCeScUC1n5LdfobrtPFnJhAeM7cdzZIKcapP2P08EzOvO9MVEKQb+RCKIZxG/pmnJhA2I1sc++ZLqHLnnjZ6NE1OfO+U4CmCghyBk/vFcO4Fm9bTkxAjLbyn5c9at10Iec9AOYosUeewoVQihvZoFYp8nCZlf/c43aH/KbRY+tw3gPhVgUEmYXP1aI5V0kxFpnf2YMoEM3dxZBfNXpsLc56IKxD5cAF+QIug1I0MlylvpyYAHnMyoP2ivPcCPKLRg+tzjkPiFcV2CNv4DIohHGG+jOcmAA5YN1aYoOuSW5vyrTzoMhX4GiPtZFVIstwjUZwYgLld1Sz8qGfxSnJCvIAw8YkzEMOjCXICFiQ2RxIHQpM+oW8yakJmK+sIskQX2Qdl5wg32f8wC2c8cAYGLAgP8glUAb2C1GX0dZ+9FJyMeR2xo9bwfkOjL2oH6ggM8dVHZabrNEsTo0C9LH2pJuTEeRLjR82j7MdIME2P72MC6AMOWDxL5UDSpaJqvvSsp0LcjXjh33M2Q6UhwIU5PqcfmV4l5kwin+bbWblS6sq/NepIJ9h/KhXONcBL/TFgQkyK4mpw8swPnQ/wKlRhI3WpXM/dVrf4iixz+hBvTnTAfMjygckyPU4+crQG7y4pTrLUNXKn/o6vTy9xOgxHTnPgTM0IEFuzKlXBuM+bs05MUoxy/IytXals8S3qUaPacRZDpwCXMfeeimO8dfhuzgxivG6lUdtLXeWkx3yEOOKyIWc5cBZj3MCEOQenHhF2GVyLWQQp0Y5ulpHksvYP9a72/ghGznHCjAlAEF+ndOuCN+brNBkTo1y7LOub3GH/ZDFlcaPWMA5VoL7fRfkhZx0RZhkskI/c2oUZKXV4d7ueHm7O+RMFipXmf24wlc5roaDnHRFML4Jls6kN0WZYRJiEhAQc2wmwGUdJ/KNHvAC51cRfkcVHwW5GydcGa4xXKFLOTHK8riVb/W0e6y3ko6pNu/5KMg5nG5FyENF5liEbs3amPvWfr2avaDFZ+xrqzoP+ZaDzOwaVfjZZI1e5NQozAarzKhvYkfZ2SEPN/pwFbqmQhzAVb4I8iecamUYb7JGn3FqlGaShX/pt9gR5G4sYKI+q6wvaEoZ13GaFaKnySqt4dQozi3mPrbFRrmh+FWMJoaB6VZnuBJGZazkJCvEJaxjEVK2Itt8j/xiYkGuYPzRMZxZxRjsoRzrmMoJVsqpjf/83sGpCcXmyczPtDytUiJFPkYcZMW3MFCAjp4J8jBOr1J8YrJOIzk1oeAuc1+bnDiKvJStfMLBbjTyRI5ZHUE1+pus1PecmlCw2eL2QLxWUhXf6nBWFeRX6ddEMjGR06ocTQ3XqiLvUYaGYeY+916iTOTBxh/cxVlVMj4l83DvEvZnU5BdJhV2W3FqQsNBNDTzusIE3fbE7cYfXMxZVZKnJIlxJQxhXQQlmWGyYk9yakK1dTI9Qh9nHbK4yPhjH3JOlaQAN0tIcuuHTZxKReltsmozOTWh4iYz/zsg/s8qZKHx5D1cbEcDF2LcFOOxm5OoMBeZ1HnbzqkJFYvNvbCPZeKblsfeEeFiRRKHew3QA5N5A1N51pqs39WcmtDR1swb/7Csa2Fc8a0N51NhPrE83KuMy9EMbXELumMIJmMBtnLKQsJbJmv6FKcmdOSY+2gDK0H+wugjdTmfSvOEhSBn4VdOUEjpzNKoEaKp2Z29kVaC/LrRR8qz4pvSFKCDhSRfhj2cohCSj+omOcj7OTkh5EMzD91oEbQQjxt/KJfzqTTbLA/37uEEhRCz1qa8ORtO8kxLDVnc2BP3Gn9kCedTcZagMjtIR4qhJmv5EqcmpJi1l9AfNU98a238kVmcTeV530KQMzCPExQyWoPXtKLFHDP//NhckOsbf2QyZzMEDLSQ5HOxkRMUInYjw3AdqyOfkxNS8nGusXdujZUxEeS0LGN3HsfZDMWCWx3utWBBmhAxg+cBEaSHWaaFbhZDFqy+GmasD/cGcIJCg9ml6SmcmhAzziyK3NhEkDNON/7AC5zLkGB9uMfQU1gw/sMaxxZOTYhZZLZD7mIiyGX/wcLlYedji5t7lbGMExQCfjVZv2s5NaFmv8nJgP6YeeJbodEH+nMuQ8TjFnvkhtjJCVKekSarN5RTE8lvPvow87563CGHnny0s5DkW3jvUnnMStGwiUDYucZZXWRxgrEhDOFMhoptqGchycM5QUqzG+UN1602/5SGntbOBDnzZGMXfpkzGTJ+RkVTQU7HfE6Qwph1mmYZ3PDTwnhtXzcR5PT/GZvCaM5k6HjLYo9ch9VJFMYsW/UTTk3oqW28ti+ZNXGqYWwK7EccRh60kOSO/PqrKIWoA+Oai+zuEnb2mGRAaQ+bCHL8KmP3/YZzGUL2m9ZgFRAYxQlSkp9Z5S2ymLZyutlsh9zF+APrOJehZB1qWBQcWsgJUpAXTdbrVU5N6HnOrADnuWZZFs8Zuy4LmoSVHKSbSnJ95iQrSEuT1fqNUxN6LjUOWOSV/YfZDnm+cVNMEr2/ygICnTk9irHd5A8ofTD8/GLmh/NM5DjrJOOu0x05lyEmH9dZSPIbnCClMKtq3ZdTE3o6mXlhP7OAxeW8sBlFNpvVYYVABfzECVKGj3COyTp9yckJOfNNfVCvbRawGMkut9HkC4uCQxezCaoSbMGtFkWh2Ng03Bw0z3haZlKePvtYbbNxl9u9nM/QY1Vw6BFOjwJ/Mmtb1h8h4aav+eo+6DBg0YGzGQHyzC5tQkDH55ygANmO+yzEWEDgTU5SqLEoibsj7VQzQX6Nxz5RZg2qmTp8NgufB8ZMk5t5vAcQFRZYNY143CzD4jix1bgQDV01KkyzcPnbOD0BsAXdE4qxwJWcqBCzEFnma7u17Glm/aabGn+kHWc0QvSwcPt3OT0+M8XiHmXR8TSnKrTMR1Wrtb3DtFOIPs74IxM4pxFij0UT1KrYwAnyjVW4yZYYCwh8x+kKKVMtiuAK6Dmxo80L0+8wvjTNMo1R+4udblEBjvjBPgxBBdtyXJ2FC0JJIYZYJJsKaLvKpZvvj682/tDNnNfIMdDCSKZyejxnpmU3l9KjK6cshGxBxwTrqt0QM0e8xLhiqnAAl5kaSU1+I/KU3xK6aenxAactdHxlmVUuIKANjVkhfjO+VstqYFHkJ5OebQICt/NOmEfswACTJvBWI51/IkPGHvS2DFUICIgpsWMs5DhenjHF1OIFC2NpwHYE0inAZGQ7FmMBgeacvFDxBS5MuKbajIzjLffH+l3GHxzL+Y0oebjawmDi6MP6FhKZgcZJibGAwLOcvtCwDb3srOmcrJNi1mhTjT+6inMcWZYk+Pp8IWZzkiSwEG2SFmMBwf7godnijEZ1Oyv6dfzfCeQ46zhtl9FH63GWI82AhMZzH29puvyj19GVGAtUQR6nMQTk2P0O9K5pb5Ai++OLjT/8KOc50uy1Ee2qhlGUhKRYhrsRdynHAndwIkOw0u3trufzsaNiidEHGn/8U851xPnElhldhC84VQ5dtLvF9RsnYzwnU2nWoZfNldbyROeYPcRM43QbprxFn1ts79RWc7Jshik6S9gZ/zU46+qSi0H271v+kVbXphzHyohtRo9oxRlPAdZaFQYsNjIxAFs5YZbMRcfEGagOxsWcUkXZhIG2PUdATDat6WY/B3kwZz0lGOFAICpjEHZwygwowExcK1GKD43enFgF2YC+liWDSoy9FhXdDI/02ho/6BPOfEqQh4sciUQNjMQ+TlsR9mCsRQ09N2MaJ1cx1qGfEzGG9pWoGHOGeM74USzFmCpMcywUdTCKF0cAAL+jL6p4IsYCOpMOlWIt+iHTyQpuF/fayqoosUP+yuhhtTj/KUSLpDJk++HPlA5S5KCT1IhxydGYhqkMq9HLaR2SyeXOiiXB0WI3q1ikOvOSlIwK6J6Stzk3YDjqeyjFjCCrxDJ0dZrE+LPeOJYc5dKNHzmE65BSJH+jLAN34hsUpsg87cd7aCsxrY0RZLX5xXlGea7okXVcLFn0xrwUQoClLi8yNMLrEc9bL8Bc9LLo280IctSY7zwkdVB7wUGCm2EE+U7jRy/leqQY97uWkMroie8jOTeL8Rjq+CbFjCCrIMZtna5YoZiYnhFziz7Y+PG8pZdqrLMoWu9kXITnIxNXLsQPeNphWiAjyGFf85lo5ny9PtVqxmQg3jQuKUNSjwckft1ugbGh7nRxELPxiO+74qLjPRqk7+RjSjKVq79OuyQmC/G50Suu4NqkIL9JPqxKRxu8Errd8jpMQBdUDVCKWYs8CArwES5xvk7f6E1jMhE/Gb3mFq5PSnK7R9HQp7BQ+Vb2e/AF+qFR4EJ8aFRPmbwVVcIUTZyv0hxxWUw2Yq3Rq3pyjVKSeR5KTGW0xXAsVk5odiEHg9BSUgRd1uhAY/SNHFwV/M74iCBvN3pdH65SitLEc6nJxt14HQsD7m19AD/gDTyIRp7etUt+sJOeX2J8tTpiHIvFYlqe0SsHcqVSlDd9k5wMNMUjmIRfcMC33y4X8/AmeuEqp9dgfR8zaYo+iHES2RTfaFfEvEQUGr32Sa5WirIHWb6LTzoa4jY8hSlYLD0zYx+WYybG4BFcj2zFRbjo2ExT9JSv0dJ57lCOhzvjI4Kcz4vTpCj3BSxFlXApOuAhDMUEfIr5WIEttg4EC7Adq7EQn+FtvIj+uAvNUStEEly84zfxjhXooqYYx2KxmDhg9PpnuGop/EVORYk6B9VRHw3QFFejLdqiLZoeHpehPqo7K4uo/OhMM/SIDXjAcXKnNkM7P+YXYqvRj9CLK5eyFAR6HYKD31C9C8cNcVRcXkAUalP12jE/0VYwD5kUpzclMeDxIY1Q+jZjAmo6W4UCbWpadsxvxLdGP0wzrmAK8wUlMeCxjEYolcVO+x0WiLe0SrEgEJONW/SQ1GU/KlEUAxzpPiYCRp9c9HMWNS7Upmo1YkGhPWX8Y23iSqYwHSiLAY6GNEBJ5GOUw6ok2owAwhTFym/exm4FpCRDKYsBjltpgFJY4vTix8fxc2NBo9c2/uH6cz1TmBzKYoCD17JkhN2GOKpOoueIhjEVyDpO7Ge/AlKc3T51jeMwGu/SAF0yz1khTZn1jCUc631j/GMu5LqmMMxFDm7Mo/m5YA96OikYtciDEpouBbmv8Y96H9c2hbmewsjS9CFkERraP8Bbo98WOzqmGuI84x+3IgucpDAPURgDG3tofkmRh+H2q/jlih5l/xFTkqPESuMfuivXOGUZTGEMaFSh8SXFGtv127Q87YWyp8XURetv9qN/xXVOUV6mNAY0LqbxJcEkVLY7w1/Eq8bUJi1uXIRToB62cq1TkjcpjQGN62h8DjmAfnZnd6XWIhYGxESzX6EpI1oUZA4fxz00PkesR3N7M7tP9FE1alx6j5xt3DlEQKATDnLVU45XKI0BjcdofA6YY7cPzCw9MxYmxNvmv0wrBi5SjhcojQGNoTQ+mxRgiL0LTNvEvbGjYuFCCLHP/Feqh6Vc/5SiH6UxoDGKxmczcny3vRmdmP6/WBgRPa1+rQwMCrhxO/GT2ymNAY3xND4bbEMrO7O50adOeB7lI89OlJCTQ0tIEZpRGgMaU2h8CVmJBnbmcpp2ZizM6JrYlOiXbImZKKRFRJ7alMaAxgc0vgQstHOQt1O/LRZ+tIu1vMQm0wQTsIt2EWHyWO0tsPEezc+SaXY6jM/W9Fg00NuJAjtmUxFdMRt5tI9IsoLCyJCFkkxFeqIZLBTPZx8biw6is3lOcslRGZ0wHhtpJxHjAwojqyEryOTEcpwb5mM8813yQScmFMeV6IOp2ECLiQhPUxgDG2/Q/Ex4L7EcL0yLx6KI3lhsTcaY6qIzhmIm1tN6Qk1HCmNg4yWanyETEp9rvJxxfCyqpMXF927MqjraoCdGYiZWMtIcOtgvJLjxFM3PgPGJuoDk63fFok32saKvWRU4p+McNEUXDMJ4zMRi7KZ9Kc1KymKAoycNsBQfJtod745g5Nikm8h3XhjduWiGzhiAUfgIC7Cee2ilYKW3IEd7GmAJvk2U6LZOqxlLGY4Wd2hrvDbCOGqjGW5DHwzHFMzFakp0gNwZLgnbJ9aJJdp8bYaYoo8TI8QoMVFMFBPFFG2GvkAs0dZYVWlRb7Dfe3GW4xzrGfshvVwstcg4XtwhVvlrlumoizbojucwCd9QoH2kADXVlKrdYomYLd7WXtAf0TrqTeMXpmWVO8tehdvMk+MV0uqK5vpd2tPibTFXbFBXkLN4E7YIG3GB5WxpX2X8K5aKZB+rdRK/BGemhwT6PgzFh/gZe2mpHn5BVESa9oif9Q/1F/X79ZbxWhX+KzkYd4KeqV+q36IN0MaKOYlLBvg51tIID7MbV1rP1RdZJ8VSGe18baTYEbzJ6rgA7dAb47CAl7gl80hgq6rt0uZrY0VPvbVe2++SifF/x2uJ6/RHxBgxR9scrHXPoBECAPLQ1tpeZpx1YoycdaJ+o/hI7FVnR1EPt2AwPsJq2rAEJ/A5YLFVz9FGat3FZboWK6PMYfYp8VriOu1h8Zr4Uqy1f3OVJerlUYjuCWq5haYhk0+yfLU2UqxTK/5WEx0xBF8gl/acJLP8WKeD4gcxRuuedol+RihyjU5Iy9Kbiq7aUDFNLPP+iLADzRDAM9a746kRvgTigjLxqloX8aZYrdrRSAM8iMm8zO2YW71bk23iCzFE3KzVyDou5Ifcp+vVtCb6baKvGCU+Fj+JXLkzVZldLDHBOmSZw91xohhcmnaD9rQ2Q2xRTZh7YArLH9lkpfyym6vF+6KfaC5ExL8vZooG2jVaJ/0BMUgbKSZqM8RsfYFYJlaKXJErcrVdRbJFcrU14jfxg77A7BvmvJT/nlaqakXRGpRLyp5GxbVNern4VaKXNlabL3aqlN05CPNRQM314UBPyxM/izf1B+KNzv4P/cEyGNLeeAYfT2krXIQso6KaBw7/1/po/3H3WpwbiTvEk2KiNl+FvXMtPIiPsYfKa8hWVHIzuyv1D8Ugra2ozuieXcqdZXxgeB7yU9YKl6K6WZ3j3aJQ7NRq0G5kxd7+pZ8jmotu2gvaVPGT2B2ULGeiEz5inK4UvZ3O5AbxjXhLPK7fop2foun57hNJfzSe229SNmh2rnVOzqW0Gc9IOzVeNX6V6Cwe18aKL8XvR76U+DKqoTtmpvBOpCS/I8Nsrv4Qv+oL9AXaDDFBH6b117poV6ZV5rGKlKBFP+M5vzMlbXAd6lr3AulAi/E1Z0M7U5yntdDu04ZqU8VPYo/3snw+BjMXAwBwm9kcLVYnPziCm5Iss5upq1LOAjegvrW39qG9BB2D/p9eW28tHhTDxcdiiVcZoOm4HTkpXkHgC/MUo1a0wyCCFg+nmAWuQQNrP32NGwPldtC6pl+qddFeEJ+I3+01Y3WSIDc8ZS+U7DAvSf9T7CganqdBi3uMZ748/kghC1yNetb++UmkGpdGkbNOjNfSOopntRlio7yU/IHYlIKCfK/5nDSnpXksyKeYhea6pYz9/ZqoR833mSfTUkIV2tCuEL21qTLKKlZE3xSLKr9nPhszaVs+BC1GmlUJ/zEl7O/nRPVTlon/o5WEVZrLaddoT4tvtTw3olwe3VPmUOUn8+zjfP0cWpT3lEs3a5XWPgXs7xtUs/bGVSlXgD6KZJ0kLtMH6jnJp9JloEcK1I/70+LLov4i7cgf9HFma/BlxO1vKipY++H69AzaR4Q445/61eLlZIsfRV2Ud6GZxc27FC/+7SPx8uKg8SrUjfS90tEJaqdom9OyaB3R3INUEz3E7GS6aGegO1ZG0h32oI1FEj7vRPlqny+arcSgiIpxIZ5I5Hvb07JpGdE+PjlT3Cu+cV5wPAP3Y1nEHGI3WloVOBxGa/H17ON/ZqW40vFTBOV4t/lFpCPXpOO1aBepYfzlxL16jvO2UTdHqMLAJqtgBcQPvBjt+x75UbPVaBq5uiu/45JE/vYnD5RTbbdcU3vFtMBRoblzfBiB+hdLrHv57oiXp334f9oh1putyMBIyfGsRHkVEOu0SrSIVDxM+bd+t0Ev7ULroMb5GIrNIXaI6Ub1ZouWAm9Gywhkj3yj+bezzyMTOX4xcROEP5hZkdKIhuL9ohJsJ4e5PLqEsv7FPvSDbn2y3Z0WEZglfmLeLTIKl5VycXPi4OBSXaMlcHdyjph4uDpGvv0qGZdjdKjqX/yAixP9Ti/RFgIUZGFeJfxa7Au5HM/BeYl9ag67zJDDpFXWxmp5TmvKpaNtKMrd70C/0p3KSu6OJ8WOph0EKsndzFenc4hbkOVjSELrExDvnXUibYAUjSqX115J5tp1TfTDd8qGMAowHjUS/xZTYsfQAgLmaDHXfIWeDG1WRQs7eUzDuB0gBpRLF6OTq4VRB/2Ua6VagI8SJxlBQExhLzwVSM8Q281XaVzoxLgAr6BiYusrFD259sQqmjci2QJFddAHX2K/Ekd4ExKV/f5rjOHuWJnzjJZW2fBjQyXHf1jdBv07VLZLu4brThLulPVXxf7ky3i2xWisDcwVfsMgO2GKQ+MJdmNQSpJftJLkN0MixgcxzFYfc21FWmWuObH3BfJ/oq/Y6qaU5yV4CO/jTx8dYT1es7wWXWLsZ+tI1cg4Xl9gJcljQiDHOfYCZRCfpJ3KFScOyDxZu09b47bw/UXoibex1MN7fgX4CS+jeYI845J3osR5XGElQ2aWzRZ6IU9hMf4T3e1ZYaH2FA/ySBJkH6u3szr/dtImqiX6YzIWY68k88/DTxiHLvYDFH/vtT7MOJ1rqyZp2douq7Vrj11KivEeDEcVe/a3RW/KdSaunES8JvbK6uCnox46YCDGYCaWYIcjs9+PFZiJ19ADV6F8cu/fp9/NyLHKaE2sj5WvwK/KRY3HINum/WlfsRMIkUDZ0/T7xa9yO14fGlVwCVqiE+7HY3gRwzEa4zEeUzEe4/E6huMF9ENXtEdTnOcsLGE0vtQzuZbKBy5uT/Rt6y1lxDgPU+xm9EAU6I8xq4fI4yjtIjHG/Jqr4iNXv41745BIcq9Eq9lZgcv7BzDevhhDrI434soS+Xvlf+ittBnOy90HOg6KEen/49qFKHBxX6I1rY7xAV5G2oNRFn0ZDcbEsqdxVYlnlEvXHhaLQiHGBdqkeAWuWOh2yfck/qN/NX4IQIx/RR9UdWKBa7UruZ7EB+IVFJflAjEhvQrXKaSS3DlxBUIdt/nY7OkgpqGt05OM18UpXEviqyyLB8WsZK9cezZ2iOe5Mw65JDezToL7S5RvwULPS8zPx8Oo7tQGf9Eu5iqSYJznFNFGjBGbVBBjbb7WJfNkrkn40c8Rf9hb8yswFjs9KaG5AE/iQudWuFv0zDqOK0iC5ai0bO0+bapV7S5Px0rxBGsEREqSzxBz7F8/uhtTpV0dycVUdE3i4pGAgJgcT+PaEXU4Oi1bu0+8J9b5dnQ3X3+UPXujSMbx4jknWT0V0B6v4vukr1n/gcnohUuTz3r/VruIq0YUpezZopn+mJgutniU0LZIe0G7hklFEQ+IXWbendq88mBrDMCbmJOwyNU+/IYcjMFDaOksf6L0WKa3ZLY7CcdO53TRUNyhvaDNEH+4OwLUNou54mX9tngtlpdPIet5L3mLqYjz0RQdcC96HRl3oRPa4vJkgxJGJavuyD6WK0XCyDHxtPiFWlvRSzyvvSE+Et+IZWKLwZn6XpErVovvxMfaG+I50VNvpdWM/5vTl6L75OvEWkUTLH8Tt3NzQKLpdieknZp2atqp/OpHSpJ5sva0OKiYGP+kt2ONCkJISpJWWXysiBQXiul609hRXBNCSCp/i6qjTQ24nsp2MSItiytBCCGxWEzUER8FIsoFYpbW8awTuQKEEFKE9AwxyNfboT+LvmlxzjshhBjvlE/QbxSzRL7Hu+JvRe94Vc42IYQk3iv/T79NfOJBBkaumCjas5o2IYQ4JO1UvaX2gliUuHBnwrFKe0PckV6FORSEEOIujHFK/Cr9UTFBLBYHHIjwHm2+eE27T29c7izOISGEyOYYPVNcpt+kPyCe1ceJ97UZ2gztK32BmKvNEJPFeDFCPKHfpV+t1dTP4GQRQghJYf4fTci7RwYvH54AAAAASUVORK5CYII=")]
+
+pub fn add(left: usize, right: usize) -> usize {
+ left + right
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn it_works() {
+ let result = add(2, 2);
+ assert_eq!(result, 4);
+ }
+}
fn foo();
}
+
+pub mod trait_members {
+ pub trait TraitMembers {
+ /// Some type
+ type Type;
+ /// Some function
+ fn function();
+ /// Some other function
+ fn function2();
+ }
+ pub struct HasTrait;
+ impl TraitMembers for HasTrait {
+ type Type = u8;
+ fn function() {}
+ fn function2() {}
+ }
+}
// Set the theme to dark.
local-storage: {
"rustdoc-theme": "dark",
- "rustdoc-preferred-dark-theme": "dark",
"rustdoc-use-system-theme": "false",
}
// We reload the page so the local storage settings are being used.
--- /dev/null
+// exact-check
+
+const QUERY = ['Subscriber', 'AnotherOne'];
+
+const EXPECTED = [
+ {
+ 'others': [
+ { 'path': 'reexport::fmt', 'name': 'Subscriber' },
+ { 'path': 'reexport', 'name': 'FmtSubscriber' },
+ ],
+ },
+ {
+ 'others': [
+ { 'path': 'reexport', 'name': 'AnotherOne' },
+ ],
+ },
+];
--- /dev/null
+// This test enforces that the (renamed) reexports are present in the search results.
+
+pub mod fmt {
+ pub struct Subscriber;
+}
+mod foo {
+ pub struct AnotherOne;
+}
+
+pub use foo::AnotherOne;
+pub use fmt::Subscriber as FmtSubscriber;
--- /dev/null
+// Regression test for <https://github.com/rust-lang/rust/issues/102583>.
+
+// @set impl_S = "$.index[*][?(@.docs=='impl S')].id"
+// @has "$.index[*][?(@.name=='S')].inner.impls[*]" $impl_S
+// @set is_present = "$.index[*][?(@.name=='is_present')].id"
+// @is "$.index[*][?(@.docs=='impl S')].inner.items[*]" $is_present
+// @!has "$.index[*][?(@.name=='hidden_impl')]"
+// @!has "$.index[*][?(@.name=='hidden_fn')]"
+
+#![no_std]
+
+mod private_mod {
+ pub struct S;
+
+ /// impl S
+ impl S {
+ pub fn is_present() {}
+ #[doc(hidden)]
+ pub fn hidden_fn() {}
+ }
+
+ #[doc(hidden)]
+ impl S {
+ pub fn hidden_impl() {}
+ }
+}
+
+pub use private_mod::*;
+// check-pass
// This test ensures that rustdoc does not panic on inherented associated types
// that are referred to without fully-qualified syntax.
impl Struct {
pub type AssocTy = usize;
pub const AssocConst: Self::AssocTy = 42;
- //~^ ERROR ambiguous associated type
- //~| HELP use fully-qualified syntax
- //~| ERROR ambiguous associated type
- //~| HELP use fully-qualified syntax
}
+++ /dev/null
-error[E0223]: ambiguous associated type
- --> $DIR/ambiguous-inherent-assoc-ty.rs:11:27
- |
-LL | pub const AssocConst: Self::AssocTy = 42;
- | ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<Struct as Trait>::AssocTy`
-
-error[E0223]: ambiguous associated type
- --> $DIR/ambiguous-inherent-assoc-ty.rs:11:27
- |
-LL | pub const AssocConst: Self::AssocTy = 42;
- | ^^^^^^^^^^^^^ help: use fully-qualified syntax: `<Struct as Trait>::AssocTy`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0223`.
LL | //! Linking to [foo@banana] and [`bar@banana!()`].
| ^^^
|
- = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
note: the lint level is defined here
--> $DIR/unknown-disambiguator.rs:2:9
|
LL | //! Linking to [foo@banana] and [`bar@banana!()`].
| ^^^
|
- = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: unknown disambiguator `foo`
--> $DIR/unknown-disambiguator.rs:10:34
LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello].
| ^^^
|
- = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: unknown disambiguator `foo`
--> $DIR/unknown-disambiguator.rs:10:48
LL | //! And with weird backticks: [``foo@hello``] [foo`@`hello].
| ^^^
|
- = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: unknown disambiguator ``
--> $DIR/unknown-disambiguator.rs:7:31
LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()).
| ^
|
- = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: unknown disambiguator ``
--> $DIR/unknown-disambiguator.rs:7:57
LL | //! And to [no disambiguator](@nectarine) and [another](@apricot!()).
| ^
|
- = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
+ = note: see https://doc.rust-lang.org/$CHANNEL/rustdoc/write-documentation/linking-to-items-by-name.html#namespaces-and-disambiguators for more info about disambiguators
error: aborting due to 6 previous errors
--- /dev/null
+#![deny(rustdoc::invalid_html_tags)]
+
+/// <p/>
+//~^ ERROR invalid self-closing HTML tag `p`
+pub struct A;
+
+/// <p style/>
+//~^ ERROR invalid self-closing HTML tag `p`
+pub struct B;
+
+/// <p style=""/>
+//~^ ERROR invalid self-closing HTML tag `p`
+pub struct C;
+
+/// <p style="x"/>
+//~^ ERROR invalid self-closing HTML tag `p`
+pub struct D;
+
+/// <p style="x/></p>
+//~^ ERROR unclosed quoted HTML attribute
+pub struct E;
+
+/// <p style='x/></p>
+//~^ ERROR unclosed quoted HTML attribute
+pub struct F;
+
+/// <p style="x/"></p>
+pub struct G;
+
+/// <p style="x/"/>
+//~^ ERROR invalid self-closing HTML tag `p`
+pub struct H;
+
+/// <p / >
+//~^ ERROR invalid self-closing HTML tag `p`
+pub struct I;
+
+/// <br/>
+pub struct J;
+
+/// <a href=/></a>
+pub struct K;
+
+/// <a href=//></a>
+pub struct L;
+
+/// <a href="/"/>
+//~^ ERROR invalid self-closing HTML tag `a`
+pub struct M;
+
+/// <a href=x />
+//~^ ERROR invalid self-closing HTML tag `a`
+pub struct N;
+
+/// <a href= />
+//~^ ERROR invalid self-closing HTML tag `a`
+pub struct O;
+
+/// <a href=x/></a>
+pub struct P;
+
+/// <svg><rect width=1 height=1 /></svg>
+pub struct Q;
+
+/// <svg><rect width=1 height=/></svg>
+//~^ ERROR unclosed HTML tag `rect`
+pub struct R;
+
+/// <svg / q>
+pub struct S;
--- /dev/null
+error: invalid self-closing HTML tag `p`
+ --> $DIR/invalid-html-self-closing-tag.rs:3:5
+ |
+LL | /// <p/>
+ | ^^
+ |
+note: the lint level is defined here
+ --> $DIR/invalid-html-self-closing-tag.rs:1:9
+ |
+LL | #![deny(rustdoc::invalid_html_tags)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: invalid self-closing HTML tag `p`
+ --> $DIR/invalid-html-self-closing-tag.rs:7:5
+ |
+LL | /// <p style/>
+ | ^^
+
+error: invalid self-closing HTML tag `p`
+ --> $DIR/invalid-html-self-closing-tag.rs:11:5
+ |
+LL | /// <p style=""/>
+ | ^^
+
+error: invalid self-closing HTML tag `p`
+ --> $DIR/invalid-html-self-closing-tag.rs:15:5
+ |
+LL | /// <p style="x"/>
+ | ^^
+
+error: unclosed quoted HTML attribute on tag `p`
+ --> $DIR/invalid-html-self-closing-tag.rs:19:14
+ |
+LL | /// <p style="x/></p>
+ | ^
+
+error: unclosed quoted HTML attribute on tag `p`
+ --> $DIR/invalid-html-self-closing-tag.rs:23:14
+ |
+LL | /// <p style='x/></p>
+ | ^
+
+error: invalid self-closing HTML tag `p`
+ --> $DIR/invalid-html-self-closing-tag.rs:30:5
+ |
+LL | /// <p style="x/"/>
+ | ^^
+
+error: invalid self-closing HTML tag `p`
+ --> $DIR/invalid-html-self-closing-tag.rs:34:5
+ |
+LL | /// <p / >
+ | ^^
+
+error: invalid self-closing HTML tag `a`
+ --> $DIR/invalid-html-self-closing-tag.rs:47:5
+ |
+LL | /// <a href="/"/>
+ | ^^
+
+error: invalid self-closing HTML tag `a`
+ --> $DIR/invalid-html-self-closing-tag.rs:51:5
+ |
+LL | /// <a href=x />
+ | ^^
+
+error: invalid self-closing HTML tag `a`
+ --> $DIR/invalid-html-self-closing-tag.rs:55:5
+ |
+LL | /// <a href= />
+ | ^^
+
+error: unclosed HTML tag `rect`
+ --> $DIR/invalid-html-self-closing-tag.rs:65:10
+ |
+LL | /// <svg><rect width=1 height=/></svg>
+ | ^^^^^
+
+error: aborting due to 12 previous errors
+
--- /dev/null
+// check-pass
+
+pub fn foo() {}
+
+/// [`foo`](Self::foo) //~ WARNING unresolved link to `Self::foo`
+pub use foo as bar;
--- /dev/null
+warning: unresolved link to `Self::foo`
+ --> $DIR/issue-103997.rs:5:13
+ |
+LL | /// [`foo`](Self::foo)
+ | ^^^^^^^^^ no item named `Self` in scope
+ |
+ = note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default
+
+warning: 1 warning emitted
+
--- /dev/null
+// compile-flags: -Z track-diagnostics
+// error-pattern: created at
+
+// Normalize the emitted location so this doesn't need
+// updating everytime someone adds or removes a line.
+// normalize-stderr-test ".rs:\d+:\d+" -> ".rs:LL:CC"
+
+struct A;
+struct B;
+const S: A = B;
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/track-diagnostics.rs:LL:CC
+ |
+LL | const S: A = B;
+ | ^ expected struct `A`, found struct `B`
+-Ztrack-diagnostics: created at compiler/rustc_infer/src/infer/error_reporting/mod.rs:LL:CC
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
-Z time-passes=val -- measure time of each rustc pass (default: no)
-Z tls-model=val -- choose the TLS model to use (`rustc --print tls-models` for details)
-Z trace-macros=val -- for every macro invocation, print its name and arguments (default: no)
+ -Z track-diagnostics=val -- tracks where in rustc a diagnostic was emitted
-Z translate-additional-ftl=val -- additional fluent translation to preferentially use (for testing translation)
-Z translate-directionality-markers=val -- emit directionality isolation markers in translated diagnostics
-Z translate-lang=val -- language identifier for diagnostic output
impl Bar {
// @has assoc_consts/struct.Bar.html '//*[@id="associatedconstant.F"]' \
// "const F: fn(_: &(dyn ToString + 'static))"
+ // FIXME(fmease): Hide default lifetime, render "const F: fn(_: &dyn ToString)"
pub const F: fn(_: &(ToString + 'static)) = f;
}
--- /dev/null
+// edition:2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+pub trait Foo {
+ // @has async_trait_sig/trait.Foo.html '//h4[@class="code-header"]' "async fn bar() -> i32"
+ async fn bar() -> i32;
+
+ // @has async_trait_sig/trait.Foo.html '//h4[@class="code-header"]' "async fn baz() -> i32"
+ async fn baz() -> i32 {
+ 1
+ }
+}
--- /dev/null
+// aux-build:async-trait-dep.rs
+// edition:2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+extern crate async_trait_dep;
+
+pub struct Oink {}
+
+// @has 'async_trait/struct.Oink.html' '//h4[@class="code-header"]' "async fn woof()"
+impl async_trait_dep::Meow for Oink {
+ async fn woof() {
+ todo!()
+ }
+}
--- /dev/null
+// edition:2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+pub trait Meow {
+ /// Who's a good dog?
+ async fn woof();
+}
--- /dev/null
+#![feature(rustc_attrs)]
+
+#[rustc_has_incoherent_inherent_impls]
+pub trait FooTrait {}
+
+#[rustc_has_incoherent_inherent_impls]
+pub struct FooStruct;
impl MaskedTrait for String {
fn masked_method() {}
}
+
+pub trait MaskedBlanketTrait {}
+
+impl<T> MaskedBlanketTrait for T {}
--- /dev/null
+pub struct Foo;
+
+impl Foo {
+ pub fn foo() {}
+}
// @snapshot out9 - '//*[@id="associatedtype.Out9"]/*[@class="code-header"]'
//
// @has - '//*[@id="tymethod.make"]' \
-// "fn make<F>(F, impl FnMut(&str) -> bool)\
+// "fn make<F>(_: F, _: impl FnMut(&str) -> bool)\
// where \
// F: FnOnce(u32) -> String, \
// Self::Out2<()>: Protocol<u8, Q0 = Self::Item, Q1 = ()>"
pub use aux::Main;
+
+// @has main/trait.Aid.html
+// @has - '//*[@id="associatedtype.Result"]' "type Result<'inter: 'src>"
+pub use aux::Aid;
}
pub trait Aid<'src> {
- type Result<'inter>;
+ type Result<'inter: 'src>;
}
--- /dev/null
+pub type Ty0 = dyn for<'any> FnOnce(&'any str) -> bool;
+
+pub type Ty1<'obj> = dyn std::fmt::Display + 'obj;
+
+pub type Ty2 = dyn for<'a, 'r> Container<'r, Item<'a, 'static> = ()>;
+
+pub type Ty3<'s> = &'s dyn ToString;
+
+pub fn func0(_: &(dyn Fn() + '_)) {}
+
+pub fn func1<'func>(_: &(dyn Fn() + 'func)) {}
+
+pub trait Container<'r> {
+ type Item<'a, 'ctx>;
+}
+
+pub trait Shape<'a> {}
--- /dev/null
+#![crate_name = "user"]
+
+// aux-crate:dyn_trait=dyn_trait.rs
+// edition:2021
+
+// @has user/type.Ty0.html
+// @has - '//*[@class="item-decl"]//code' "dyn for<'any> FnOnce(&'any str) -> bool + 'static"
+// FIXME(fmease): Hide default lifetime bound `'static`
+pub use dyn_trait::Ty0;
+
+// @has user/type.Ty1.html
+// @has - '//*[@class="item-decl"]//code' "dyn Display + 'obj"
+pub use dyn_trait::Ty1;
+
+// @has user/type.Ty2.html
+// @has - '//*[@class="item-decl"]//code' "dyn for<'a, 'r> Container<'r, Item<'a, 'static> = ()>"
+pub use dyn_trait::Ty2;
+
+// @has user/type.Ty3.html
+// @has - '//*[@class="item-decl"]//code' "&'s (dyn ToString + 's)"
+// FIXME(fmease): Hide default lifetime bound, render "&'s dyn ToString"
+pub use dyn_trait::Ty3;
+
+// @has user/fn.func0.html
+// @has - '//pre[@class="rust fn"]' "func0(_: &dyn Fn())"
+// FIXME(fmease): Show placeholder-lifetime bound, render "func0(_: &(dyn Fn() + '_))"
+pub use dyn_trait::func0;
+
+// @has user/fn.func1.html
+// @has - '//pre[@class="rust fn"]' "func1<'func>(_: &(dyn Fn() + 'func))"
+pub use dyn_trait::func1;
// @has impl_trait/fn.func5.html
// @has - '//pre[@class="rust fn"]' "func5("
// @has - '//pre[@class="rust fn"]' "_f: impl for<'any> Fn(&'any str, &'any str) -> bool + for<'r> Other<T<'r> = ()>,"
-// @has - '//pre[@class="rust fn"]' "_a: impl for<'alpha, 'beta> Auxiliary<'alpha, Item<'beta> = fn(&'beta ())>"
+// @has - '//pre[@class="rust fn"]' "_a: impl for<'alpha, 'beta> Auxiliary<'alpha, Item<'beta> = fn(_: &'beta ())>"
// @!has - '//pre[@class="rust fn"]' 'where'
pub use impl_trait_aux::func5;
--- /dev/null
+pub trait Trait {
+ /// [`u8::clone`]
+ fn method();
+}
--- /dev/null
+// The `Trait` is not pulled into the crate resulting in doc links in its methods being resolved.
+
+// aux-build:issue-103463-aux.rs
+
+extern crate issue_103463_aux;
+use issue_103463_aux::Trait;
+
+fn main() {}
// @has - '//*[@class="rust trait"]' 'trait Deref {'
// @has - '//*[@class="rust trait"]' 'type Target: ?Sized;'
// @has - '//*[@class="rust trait"]' \
- // "fn deref(&'a self) -> &'a Self::Target;"
+ // "fn deref<'a>(&'a self) -> &'a Self::Target;"
pub use issue_20727::Deref;
}
<code># single
## double
### triple
-<span class="attribute">#[outer]
+<span class="attr">#[outer]
#![inner]</span></code>
// @has issue_41783/struct.Foo.html
// @!hasraw - 'space'
// @!hasraw - 'comment'
-// @hasraw - '<span class="attribute">#[outer]'
-// @!hasraw - '<span class="attribute">#[outer]</span>'
+// @hasraw - '<span class="attr">#[outer]'
+// @!hasraw - '<span class="attr">#[outer]</span>'
// @hasraw - '#![inner]</span>'
-// @!hasraw - '<span class="attribute">#![inner]</span>'
+// @!hasraw - '<span class="attr">#![inner]</span>'
// @snapshot 'codeblock' - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]//pre/code'
/// ```no_run
--- /dev/null
+// This test ensures that the reexports of local items also get the doc from
+// the reexport.
+
+#![crate_name = "foo"]
+
+// @has 'foo/fn.g.html'
+// @has - '//*[@class="rustdoc-toggle top-doc"]/*[@class="docblock"]' \
+// 'outer module inner module'
+
+mod inner_mod {
+ /// inner module
+ pub fn g() {}
+}
+
+/// outer module
+pub use inner_mod::g;
// @!hasraw 'search-index.js' 'masked_method'
// @!hasraw 'foo/struct.String.html' 'MaskedTrait'
+// @!hasraw 'foo/struct.String.html' 'MaskedBlanketTrait'
// @!hasraw 'foo/struct.String.html' 'masked_method'
pub use std::string::String;
--- /dev/null
+// This test ensures that the tuple struct fields are not generated in the
+// search index.
+
+// @!hasraw search-index.js '"0"'
+// @!hasraw search-index.js '"1"'
+// @hasraw search-index.js '"foo_a"'
+// @hasraw search-index.js '"bar_a"'
+
+pub struct Bar(pub u32, pub u8);
+pub struct Foo {
+ pub foo_a: u8,
+}
+pub enum Enum {
+ Foo(u8),
+ Bar {
+ bar_a: u8,
+ },
+}
--- /dev/null
+// aux-build:reexport-doc-aux.rs
+
+extern crate reexport_doc_aux as dep;
+
+// @has 'reexport_doc/struct.Foo.html'
+// @count - '//p' 'These are the docs for Foo.' 1
+/// These are the docs for Foo.
+pub use dep::Foo;
--- /dev/null
+// aux-build:incoherent-impl-types.rs
+// build-aux-docs
+
+#![crate_name = "foo"]
+#![feature(rustc_attrs)]
+
+extern crate incoherent_impl_types;
+
+// The only way this actually shows up is if the type gets inlined.
+#[doc(inline)]
+pub use incoherent_impl_types::FooTrait;
+
+// @has foo/trait.FooTrait.html
+// @count - '//section[@id="method.do_something"]' 1
+impl dyn FooTrait {
+ #[rustc_allow_incoherent_impl]
+ pub fn do_something() {}
+}
+
+#[doc(inline)]
+pub use incoherent_impl_types::FooStruct;
+
+// @has foo/struct.FooStruct.html
+// @count - '//section[@id="method.do_something"]' 1
+impl FooStruct {
+ #[rustc_allow_incoherent_impl]
+ pub fn do_something() {}
+}
// compile-flags:-Z unstable-options --static-root-path /cache/
// @has static_root_path/struct.SomeStruct.html
-// @matchesraw - '"/cache/main\.js"'
-// @!matchesraw - '"\.\./main\.js"'
+// @matchesraw - '"/cache/main-'
+// @!matchesraw - '"\.\./main'
// @matchesraw - 'data-root-path="\.\./"'
// @!matchesraw - '"/cache/search-index\.js"'
pub struct SomeStruct;
// @has src/static_root_path/static-root-path.rs.html
-// @matchesraw - '"/cache/source-script\.js"'
-// @!matchesraw - '"\.\./\.\./source-script\.js"'
+// @matchesraw - '"/cache/source-script-'
+// @!matchesraw - '"\.\./\.\./source-script'
// @matchesraw - '"\.\./\.\./source-files.js"'
// @!matchesraw - '"/cache/source-files\.js"'
// @has settings.html
-// @matchesraw - '/cache/settings\.js'
-// @!matchesraw - '\./settings\.js'
+// @matchesraw - '/cache/settings-'
+// @!matchesraw - '\../settings'
//~^ ERROR unsupported type attribute for diagnostic derive enum
enum DiagnosticOnEnum {
Foo,
-//~^ ERROR diagnostic slug not specified
+ //~^ ERROR diagnostic slug not specified
Bar,
-//~^ ERROR diagnostic slug not specified
+ //~^ ERROR diagnostic slug not specified
}
#[derive(Diagnostic)]
#[diag(compiletest_example, code = "E0123")]
struct Suggest {
#[suggestion(suggestion, code = "This is the suggested code")]
- #[suggestion_short(suggestion, code = "This is the suggested code")]
- #[suggestion_hidden(suggestion, code = "This is the suggested code")]
- #[suggestion_verbose(suggestion, code = "This is the suggested code")]
+ #[suggestion(suggestion, code = "This is the suggested code", style = "normal")]
+ #[suggestion(suggestion, code = "This is the suggested code", style = "short")]
+ #[suggestion(suggestion, code = "This is the suggested code", style = "hidden")]
+ #[suggestion(suggestion, code = "This is the suggested code", style = "verbose")]
suggestion: (Span, Applicability),
}
#[derive(LintDiagnostic)]
#[diag(compiletest_example)]
-struct LintsGood {
-}
+struct LintsGood {}
#[derive(LintDiagnostic)]
#[diag(compiletest_example)]
#[diag(compiletest_example)]
struct SubdiagnosticBad {
#[subdiagnostic(bad)]
-//~^ ERROR `#[subdiagnostic(bad)]` is not a valid attribute
+ //~^ ERROR `#[subdiagnostic(bad)]` is not a valid attribute
note: Note,
}
#[diag(compiletest_example)]
struct SubdiagnosticBadStr {
#[subdiagnostic = "bad"]
-//~^ ERROR `#[subdiagnostic = ...]` is not a valid attribute
+ //~^ ERROR `#[subdiagnostic = ...]` is not a valid attribute
note: Note,
}
#[diag(compiletest_example)]
struct SubdiagnosticBadTwice {
#[subdiagnostic(bad, bad)]
-//~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
+ //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
note: Note,
}
#[diag(compiletest_example)]
struct SubdiagnosticBadLitStr {
#[subdiagnostic("bad")]
-//~^ ERROR `#[subdiagnostic("...")]` is not a valid attribute
+ //~^ ERROR `#[subdiagnostic("...")]` is not a valid attribute
note: Note,
}
#[diag(compiletest_example)]
struct SubdiagnosticEagerLint {
#[subdiagnostic(eager)]
-//~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
+ //~^ ERROR `#[subdiagnostic(...)]` is not a valid attribute
note: Note,
}
// after the `span_suggestion` call - which breaks eager translation.
#[derive(Subdiagnostic)]
-#[suggestion_short(
- use_instead,
- applicability = "machine-applicable",
- code = "{correct}"
-)]
+#[suggestion(use_instead, applicability = "machine-applicable", code = "{correct}")]
pub(crate) struct SubdiagnosticWithSuggestion {
#[primary_span]
span: Span,
//~^ ERROR `code = "..."`/`code(...)` must contain only string literals
sub: Span,
}
+
+#[derive(Diagnostic)]
+#[diag(compiletest_example)]
+struct SuggestionStyleGood {
+ #[suggestion(code = "", style = "hidden")]
+ sub: Span,
+}
| ^^^^^^^^^^^^^^^
error: suggestion without `code = "..."`
- --> $DIR/diagnostic-derive.rs:223:5
+ --> $DIR/diagnostic-derive.rs:224:5
|
LL | #[suggestion(suggestion)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: `#[suggestion(nonsense = ...)]` is not a valid attribute
- --> $DIR/diagnostic-derive.rs:231:18
+ --> $DIR/diagnostic-derive.rs:232:18
|
LL | #[suggestion(nonsense = "bar")]
| ^^^^^^^^^^^^^^^^
|
- = help: only `code` and `applicability` are valid nested attributes
+ = help: only `style`, `code` and `applicability` are valid nested attributes
error: suggestion without `code = "..."`
- --> $DIR/diagnostic-derive.rs:231:5
+ --> $DIR/diagnostic-derive.rs:232:5
|
LL | #[suggestion(nonsense = "bar")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `#[suggestion(msg = ...)]` is not a valid attribute
- --> $DIR/diagnostic-derive.rs:240:18
+ --> $DIR/diagnostic-derive.rs:241:18
|
LL | #[suggestion(msg = "bar")]
| ^^^^^^^^^^^
|
- = help: only `code` and `applicability` are valid nested attributes
+ = help: only `style`, `code` and `applicability` are valid nested attributes
error: suggestion without `code = "..."`
- --> $DIR/diagnostic-derive.rs:240:5
+ --> $DIR/diagnostic-derive.rs:241:5
|
LL | #[suggestion(msg = "bar")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
error: wrong field type for suggestion
- --> $DIR/diagnostic-derive.rs:263:5
+ --> $DIR/diagnostic-derive.rs:264:5
|
LL | / #[suggestion(suggestion, code = "This is suggested code")]
LL | |
= help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)`
error: specified multiple times
- --> $DIR/diagnostic-derive.rs:279:24
+ --> $DIR/diagnostic-derive.rs:280:24
|
LL | suggestion: (Span, Span, Applicability),
| ^^^^
|
note: previously specified here
- --> $DIR/diagnostic-derive.rs:279:18
+ --> $DIR/diagnostic-derive.rs:280:18
|
LL | suggestion: (Span, Span, Applicability),
| ^^^^
error: specified multiple times
- --> $DIR/diagnostic-derive.rs:287:33
+ --> $DIR/diagnostic-derive.rs:288:33
|
LL | suggestion: (Applicability, Applicability, Span),
| ^^^^^^^^^^^^^
|
note: previously specified here
- --> $DIR/diagnostic-derive.rs:287:18
+ --> $DIR/diagnostic-derive.rs:288:18
|
LL | suggestion: (Applicability, Applicability, Span),
| ^^^^^^^^^^^^^
error: `#[label = ...]` is not a valid attribute
- --> $DIR/diagnostic-derive.rs:294:5
+ --> $DIR/diagnostic-derive.rs:295:5
|
LL | #[label = "bar"]
| ^^^^^^^^^^^^^^^^
error: specified multiple times
- --> $DIR/diagnostic-derive.rs:445:44
+ --> $DIR/diagnostic-derive.rs:446:44
|
LL | #[suggestion(suggestion, code = "...", applicability = "maybe-incorrect")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: previously specified here
- --> $DIR/diagnostic-derive.rs:447:24
+ --> $DIR/diagnostic-derive.rs:448:24
|
LL | suggestion: (Span, Applicability),
| ^^^^^^^^^^^^^
error: invalid applicability
- --> $DIR/diagnostic-derive.rs:453:44
+ --> $DIR/diagnostic-derive.rs:454:44
|
LL | #[suggestion(suggestion, code = "...", applicability = "batman")]
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: `#[label(foo)]` is not a valid attribute
- --> $DIR/diagnostic-derive.rs:516:20
+ --> $DIR/diagnostic-derive.rs:517:20
|
LL | #[label(label, foo)]
| ^^^
= help: a diagnostic slug must be the first argument to the attribute
error: `#[label(foo = ...)]` is not a valid attribute
- --> $DIR/diagnostic-derive.rs:524:20
+ --> $DIR/diagnostic-derive.rs:525:20
|
LL | #[label(label, foo = "...")]
| ^^^^^^^^^^^
error: `#[label(foo(...))]` is not a valid attribute
- --> $DIR/diagnostic-derive.rs:532:20
+ --> $DIR/diagnostic-derive.rs:533:20
|
LL | #[label(label, foo("..."))]
| ^^^^^^^^^^
= help: eager subdiagnostics are not supported on lints
error: expected at least one string literal for `code(...)`
- --> $DIR/diagnostic-derive.rs:779:18
+ --> $DIR/diagnostic-derive.rs:775:18
|
LL | #[suggestion(code())]
| ^^^^^^
error: `code(...)` must contain only string literals
- --> $DIR/diagnostic-derive.rs:787:23
+ --> $DIR/diagnostic-derive.rs:783:23
|
LL | #[suggestion(code(foo))]
| ^^^
error: `code = "..."`/`code(...)` must contain only string literals
- --> $DIR/diagnostic-derive.rs:795:18
+ --> $DIR/diagnostic-derive.rs:791:18
|
LL | #[suggestion(code = 3)]
| ^^^^^^^^
| ^^^^^^^^ not found in `rustc_errors::fluent`
error[E0277]: the trait bound `Hello: IntoDiagnosticArg` is not satisfied
- --> $DIR/diagnostic-derive.rs:338:10
+ --> $DIR/diagnostic-derive.rs:339:10
|
LL | #[derive(Diagnostic)]
| ^^^^^^^^^^ the trait `IntoDiagnosticArg` is not implemented for `Hello`
#![crate_type = "lib"]
extern crate rustc_errors;
+extern crate rustc_macros;
extern crate rustc_session;
extern crate rustc_span;
-extern crate rustc_macros;
use rustc_errors::Applicability;
-use rustc_span::Span;
use rustc_macros::Subdiagnostic;
+use rustc_span::Span;
#[derive(Subdiagnostic)]
#[label(parser_add_paren)]
#[primary_span]
span: Span,
var: String,
- }
+ },
}
#[derive(Subdiagnostic)]
#[primary_span]
span: Span,
var: String,
- }
+ },
}
#[derive(Subdiagnostic)]
#[primary_span]
span: Span,
var: String,
- }
+ },
}
#[derive(Subdiagnostic)]
#[primary_span]
span: Span,
var: String,
- }
+ },
}
#[derive(Subdiagnostic)]
#[primary_span]
span: Span,
var: String,
- }
+ },
}
#[derive(Subdiagnostic)]
#[primary_span]
span: Span,
var: String,
- }
+ },
}
#[derive(Subdiagnostic)]
#[primary_span]
span: Span,
var: String,
- }
+ },
}
#[derive(Subdiagnostic)]
#[primary_span]
span: Span,
var: String,
- }
+ },
}
#[derive(Subdiagnostic)]
#[primary_span]
span: Span,
#[skip_arg]
- z: Z
+ z: Z,
}
#[derive(Subdiagnostic)]
union AC {
-//~^ ERROR unexpected unsupported untagged union
+ //~^ ERROR unexpected unsupported untagged union
span: u32,
- b: u64
+ b: u64,
}
#[derive(Subdiagnostic)]
#[applicability]
applicability: Applicability,
var: String,
- }
+ },
}
#[derive(Subdiagnostic)]
}
#[derive(Subdiagnostic)]
-#[suggestion(parser_add_paren, code ="...", applicability = "foo")]
+#[suggestion(parser_add_paren, code = "...", applicability = "foo")]
//~^ ERROR invalid applicability
struct AO {
#[primary_span]
#[derive(Subdiagnostic)]
#[help(parser_add_paren)]
struct AP {
- var: String
+ var: String,
}
#[derive(Subdiagnostic)]
}
#[derive(Subdiagnostic)]
-#[suggestion(parser_add_paren, code ="...", applicability = "machine-applicable")]
+#[suggestion(parser_add_paren, code = "...", applicability = "machine-applicable")]
struct AS {
#[primary_span]
span: Span,
#[primary_span]
span: Span,
var: String,
- }
+ },
}
#[derive(Subdiagnostic)]
-#[suggestion(parser_add_paren, code ="{var}", applicability = "machine-applicable")]
+#[suggestion(parser_add_paren, code = "{var}", applicability = "machine-applicable")]
struct AU {
#[primary_span]
span: Span,
}
#[derive(Subdiagnostic)]
-#[suggestion(parser_add_paren, code ="{var}", applicability = "machine-applicable")]
+#[suggestion(parser_add_paren, code = "{var}", applicability = "machine-applicable")]
//~^ ERROR `var` doesn't refer to a field on this type
struct AV {
#[primary_span]
#[derive(Subdiagnostic)]
enum AW {
- #[suggestion(parser_add_paren, code ="{var}", applicability = "machine-applicable")]
+ #[suggestion(parser_add_paren, code = "{var}", applicability = "machine-applicable")]
A {
#[primary_span]
span: Span,
var: String,
- }
+ },
}
#[derive(Subdiagnostic)]
enum AX {
- #[suggestion(parser_add_paren, code ="{var}", applicability = "machine-applicable")]
-//~^ ERROR `var` doesn't refer to a field on this type
+ #[suggestion(parser_add_paren, code = "{var}", applicability = "machine-applicable")]
+ //~^ ERROR `var` doesn't refer to a field on this type
A {
#[primary_span]
span: Span,
- }
+ },
}
#[derive(Subdiagnostic)]
/// ..and the field
#[primary_span]
span: Span,
- }
+ },
}
#[derive(Subdiagnostic)]
span: Span,
r#type: String,
}
+
+#[derive(Subdiagnostic)]
+#[suggestion(parser_add_paren, code = "")]
+struct SuggestionStyleDefault {
+ #[primary_span]
+ sub: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(parser_add_paren, code = "", style = "short")]
+struct SuggestionStyleShort {
+ #[primary_span]
+ sub: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(parser_add_paren, code = "", style = "hidden")]
+struct SuggestionStyleHidden {
+ #[primary_span]
+ sub: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(parser_add_paren, code = "", style = "verbose")]
+struct SuggestionStyleVerbose {
+ #[primary_span]
+ sub: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(parser_add_paren, code = "", style = "tool-only")]
+struct SuggestionStyleToolOnly {
+ #[primary_span]
+ sub: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(parser_add_paren, code = "", style = "hidden", style = "normal")]
+//~^ ERROR specified multiple times
+//~| NOTE previously specified here
+struct SuggestionStyleTwice {
+ #[primary_span]
+ sub: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion_hidden(parser_add_paren, code = "")]
+//~^ ERROR #[suggestion_hidden(...)]` is not a valid attribute
+struct SuggestionStyleOldSyntax {
+ #[primary_span]
+ sub: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion_hidden(parser_add_paren, code = "", style = "normal")]
+//~^ ERROR #[suggestion_hidden(...)]` is not a valid attribute
+struct SuggestionStyleOldAndNewSyntax {
+ #[primary_span]
+ sub: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(parser_add_paren, code = "", style = "foo")]
+//~^ ERROR invalid suggestion style
+struct SuggestionStyleInvalid1 {
+ #[primary_span]
+ sub: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(parser_add_paren, code = "", style = 42)]
+//~^ ERROR `#[suggestion(style = ...)]` is not a valid attribute
+struct SuggestionStyleInvalid2 {
+ #[primary_span]
+ sub: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(parser_add_paren, code = "", style)]
+//~^ ERROR `#[suggestion(style)]` is not a valid attribute
+struct SuggestionStyleInvalid3 {
+ #[primary_span]
+ sub: Span,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(parser_add_paren, code = "", style("foo"))]
+//~^ ERROR `#[suggestion(style(...))]` is not a valid attribute
+struct SuggestionStyleInvalid4 {
+ #[primary_span]
+ sub: Span,
+}
LL | / union AC {
LL | |
LL | | span: u32,
-LL | | b: u64
+LL | | b: u64,
LL | | }
| |_^
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: invalid applicability
- --> $DIR/subdiagnostic-derive.rs:430:45
+ --> $DIR/subdiagnostic-derive.rs:430:46
|
-LL | #[suggestion(parser_add_paren, code ="...", applicability = "foo")]
- | ^^^^^^^^^^^^^^^^^^^^^
+LL | #[suggestion(parser_add_paren, code = "...", applicability = "foo")]
+ | ^^^^^^^^^^^^^^^^^^^^^
error: suggestion without `#[primary_span]` field
--> $DIR/subdiagnostic-derive.rs:448:1
| ^^^^^^^^
error: `var` doesn't refer to a field on this type
- --> $DIR/subdiagnostic-derive.rs:482:38
+ --> $DIR/subdiagnostic-derive.rs:482:39
|
-LL | #[suggestion(parser_add_paren, code ="{var}", applicability = "machine-applicable")]
- | ^^^^^^^
+LL | #[suggestion(parser_add_paren, code = "{var}", applicability = "machine-applicable")]
+ | ^^^^^^^
error: `var` doesn't refer to a field on this type
- --> $DIR/subdiagnostic-derive.rs:501:42
+ --> $DIR/subdiagnostic-derive.rs:501:43
|
-LL | #[suggestion(parser_add_paren, code ="{var}", applicability = "machine-applicable")]
- | ^^^^^^^
+LL | #[suggestion(parser_add_paren, code = "{var}", applicability = "machine-applicable")]
+ | ^^^^^^^
error: `#[suggestion_part]` is not a valid attribute
--> $DIR/subdiagnostic-derive.rs:524:5
LL | #[multipart_suggestion(parser_add_paren, code = "...", applicability = "machine-applicable")]
| ^^^^^^^^^^^^
|
- = help: only `applicability` is a valid nested attributes
+ = help: only `style` and `applicability` are valid nested attributes
error: multipart suggestion without any `#[suggestion_part(...)]` fields
--> $DIR/subdiagnostic-derive.rs:536:1
LL | #[suggestion_part(code = 3)]
| ^^^^^^^^
+error: specified multiple times
+ --> $DIR/subdiagnostic-derive.rs:746:61
+ |
+LL | #[suggestion(parser_add_paren, code = "", style = "hidden", style = "normal")]
+ | ^^^^^^^^^^^^^^^^
+ |
+note: previously specified here
+ --> $DIR/subdiagnostic-derive.rs:746:43
+ |
+LL | #[suggestion(parser_add_paren, code = "", style = "hidden", style = "normal")]
+ | ^^^^^^^^^^^^^^^^
+
+error: `#[suggestion_hidden(...)]` is not a valid attribute
+ --> $DIR/subdiagnostic-derive.rs:755:1
+ |
+LL | #[suggestion_hidden(parser_add_paren, code = "")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: Use `#[suggestion(..., style = "hidden")]` instead
+
+error: `#[suggestion_hidden(...)]` is not a valid attribute
+ --> $DIR/subdiagnostic-derive.rs:763:1
+ |
+LL | #[suggestion_hidden(parser_add_paren, code = "", style = "normal")]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = help: Use `#[suggestion(..., style = "hidden")]` instead
+
+error: invalid suggestion style
+ --> $DIR/subdiagnostic-derive.rs:771:51
+ |
+LL | #[suggestion(parser_add_paren, code = "", style = "foo")]
+ | ^^^^^
+ |
+ = help: valid styles are `normal`, `short`, `hidden`, `verbose` and `tool-only`
+
+error: `#[suggestion(style = ...)]` is not a valid attribute
+ --> $DIR/subdiagnostic-derive.rs:779:43
+ |
+LL | #[suggestion(parser_add_paren, code = "", style = 42)]
+ | ^^^^^^^^^^
+
+error: `#[suggestion(style)]` is not a valid attribute
+ --> $DIR/subdiagnostic-derive.rs:787:43
+ |
+LL | #[suggestion(parser_add_paren, code = "", style)]
+ | ^^^^^
+ |
+ = help: a diagnostic slug must be the first argument to the attribute
+
+error: `#[suggestion(style(...))]` is not a valid attribute
+ --> $DIR/subdiagnostic-derive.rs:795:43
+ |
+LL | #[suggestion(parser_add_paren, code = "", style("foo"))]
+ | ^^^^^^^^^^^^
+
error: cannot find attribute `foo` in this scope
--> $DIR/subdiagnostic-derive.rs:63:3
|
LL | #[label(slug)]
| ^^^^ not found in `rustc_errors::fluent`
-error: aborting due to 72 previous errors
+error: aborting due to 79 previous errors
For more information about this error, try `rustc --explain E0425`.
--- /dev/null
+// This test check that even if we mixup target feature of function with homogenous floats,
+// the abi is sound and still produce the right answer.
+//
+// This is basically the same test as src/test/ui/simd/target-feature-mixup.rs but for floats and
+// without #[repr(simd)]
+
+// run-pass
+// ignore-emscripten
+// ignore-sgx no processes
+
+#![feature(avx512_target_feature)]
+
+#![allow(overflowing_literals)]
+#![allow(unused_variables)]
+
+use std::process::{Command, ExitStatus};
+use std::env;
+
+fn main() {
+ if let Some(level) = env::args().nth(1) {
+ return test::main(&level)
+ }
+
+ match std::env::var("TARGET") {
+ Ok(s) => {
+ // Skip this tests on i586-unknown-linux-gnu where sse2 is disabled
+ if s.contains("i586") {
+ return
+ }
+ }
+ Err(_) => return,
+ }
+
+ let me = env::current_exe().unwrap();
+ for level in ["sse", "avx", "avx512"].iter() {
+ let status = Command::new(&me).arg(level).status().unwrap();
+ if status.success() {
+ println!("success with {}", level);
+ continue
+ }
+
+ // We don't actually know if our computer has the requisite target features
+ // for the test below. Testing for that will get added to libstd later so
+ // for now just assume sigill means this is a machine that can't run this test.
+ if is_sigill(status) {
+ println!("sigill with {}, assuming spurious", level);
+ continue
+ }
+ panic!("invalid status at {}: {}", level, status);
+ }
+}
+
+#[cfg(unix)]
+fn is_sigill(status: ExitStatus) -> bool {
+ use std::os::unix::prelude::*;
+ status.signal() == Some(4)
+}
+
+#[cfg(windows)]
+fn is_sigill(status: ExitStatus) -> bool {
+ status.code() == Some(0xc000001d)
+}
+
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+#[allow(nonstandard_style)]
+mod test {
+ #[derive(PartialEq, Debug, Clone, Copy)]
+ struct f32x2(f32, f32);
+
+ #[derive(PartialEq, Debug, Clone, Copy)]
+ struct f32x4(f32, f32, f32, f32);
+
+ #[derive(PartialEq, Debug, Clone, Copy)]
+ struct f32x8(f32, f32, f32, f32, f32, f32, f32, f32);
+
+ pub fn main(level: &str) {
+ unsafe {
+ main_normal(level);
+ main_sse(level);
+ if level == "sse" {
+ return
+ }
+ main_avx(level);
+ if level == "avx" {
+ return
+ }
+ main_avx512(level);
+ }
+ }
+
+ macro_rules! mains {
+ ($(
+ $(#[$attr:meta])*
+ unsafe fn $main:ident(level: &str) {
+ ...
+ }
+ )*) => ($(
+ $(#[$attr])*
+ unsafe fn $main(level: &str) {
+ let m128 = f32x2(1., 2.);
+ let m256 = f32x4(3., 4., 5., 6.);
+ let m512 = f32x8(7., 8., 9., 10., 11., 12., 13., 14.);
+ assert_eq!(id_sse_128(m128), m128);
+ assert_eq!(id_sse_256(m256), m256);
+ assert_eq!(id_sse_512(m512), m512);
+
+ if level == "sse" {
+ return
+ }
+ assert_eq!(id_avx_128(m128), m128);
+ assert_eq!(id_avx_256(m256), m256);
+ assert_eq!(id_avx_512(m512), m512);
+
+ if level == "avx" {
+ return
+ }
+ assert_eq!(id_avx512_128(m128), m128);
+ assert_eq!(id_avx512_256(m256), m256);
+ assert_eq!(id_avx512_512(m512), m512);
+ }
+ )*)
+ }
+
+ mains! {
+ unsafe fn main_normal(level: &str) { ... }
+ #[target_feature(enable = "sse2")]
+ unsafe fn main_sse(level: &str) { ... }
+ #[target_feature(enable = "avx")]
+ unsafe fn main_avx(level: &str) { ... }
+ #[target_feature(enable = "avx512bw")]
+ unsafe fn main_avx512(level: &str) { ... }
+ }
+
+ #[target_feature(enable = "sse2")]
+ unsafe fn id_sse_128(a: f32x2) -> f32x2 {
+ assert_eq!(a, f32x2(1., 2.));
+ a.clone()
+ }
+
+ #[target_feature(enable = "sse2")]
+ unsafe fn id_sse_256(a: f32x4) -> f32x4 {
+ assert_eq!(a, f32x4(3., 4., 5., 6.));
+ a.clone()
+ }
+
+ #[target_feature(enable = "sse2")]
+ unsafe fn id_sse_512(a: f32x8) -> f32x8 {
+ assert_eq!(a, f32x8(7., 8., 9., 10., 11., 12., 13., 14.));
+ a.clone()
+ }
+
+ #[target_feature(enable = "avx")]
+ unsafe fn id_avx_128(a: f32x2) -> f32x2 {
+ assert_eq!(a, f32x2(1., 2.));
+ a.clone()
+ }
+
+ #[target_feature(enable = "avx")]
+ unsafe fn id_avx_256(a: f32x4) -> f32x4 {
+ assert_eq!(a, f32x4(3., 4., 5., 6.));
+ a.clone()
+ }
+
+ #[target_feature(enable = "avx")]
+ unsafe fn id_avx_512(a: f32x8) -> f32x8 {
+ assert_eq!(a, f32x8(7., 8., 9., 10., 11., 12., 13., 14.));
+ a.clone()
+ }
+
+ #[target_feature(enable = "avx512bw")]
+ unsafe fn id_avx512_128(a: f32x2) -> f32x2 {
+ assert_eq!(a, f32x2(1., 2.));
+ a.clone()
+ }
+
+ #[target_feature(enable = "avx512bw")]
+ unsafe fn id_avx512_256(a: f32x4) -> f32x4 {
+ assert_eq!(a, f32x4(3., 4., 5., 6.));
+ a.clone()
+ }
+
+ #[target_feature(enable = "avx512bw")]
+ unsafe fn id_avx512_512(a: f32x8) -> f32x8 {
+ assert_eq!(a, f32x8(7., 8., 9., 10., 11., 12., 13., 14.));
+ a.clone()
+ }
+}
+
+#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
+mod test {
+ pub fn main(level: &str) {}
+}
#![feature(unboxed_closures)]
extern "rust-call" fn b(_i: i32) {}
-//~^ ERROR functions with the "rust-call" ABI must take a single non-self argument that is a tuple
+//~^ ERROR functions with the "rust-call" ABI must take a single non-self tuple argument
trait Tr {
extern "rust-call" fn a();
+ //~^ ERROR functions with the "rust-call" ABI must take a single non-self tuple argument
extern "rust-call" fn b() {}
- //~^ ERROR functions with the "rust-call" ABI must take a single non-self argument
+ //~^ ERROR functions with the "rust-call" ABI must take a single non-self tuple argument
}
struct Foo;
impl Foo {
extern "rust-call" fn bar() {}
- //~^ ERROR functions with the "rust-call" ABI must take a single non-self argument
+ //~^ ERROR functions with the "rust-call" ABI must take a single non-self tuple argument
}
impl Tr for Foo {
extern "rust-call" fn a() {}
- //~^ ERROR functions with the "rust-call" ABI must take a single non-self argument
+ //~^ ERROR functions with the "rust-call" ABI must take a single non-self tuple argument
}
-fn main () {
+fn main() {
b(10);
-
Foo::bar();
-
<Foo as Tr>::a();
<Foo as Tr>::b();
}
-error: functions with the "rust-call" ABI must take a single non-self argument that is a tuple
+error[E0277]: functions with the "rust-call" ABI must take a single non-self tuple argument
--> $DIR/issue-22565-rust-call.rs:3:1
|
LL | extern "rust-call" fn b(_i: i32) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `i32`
-error: functions with the "rust-call" ABI must take a single non-self argument that is a tuple
- --> $DIR/issue-22565-rust-call.rs:9:5
- |
-LL | extern "rust-call" fn b() {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: functions with the "rust-call" ABI must take a single non-self argument that is a tuple
- --> $DIR/issue-22565-rust-call.rs:16:5
+error: functions with the "rust-call" ABI must take a single non-self tuple argument
+ --> $DIR/issue-22565-rust-call.rs:17:5
|
LL | extern "rust-call" fn bar() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: functions with the "rust-call" ABI must take a single non-self argument that is a tuple
- --> $DIR/issue-22565-rust-call.rs:21:5
+error: functions with the "rust-call" ABI must take a single non-self tuple argument
+ --> $DIR/issue-22565-rust-call.rs:22:5
|
LL | extern "rust-call" fn a() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 4 previous errors
+error: functions with the "rust-call" ABI must take a single non-self tuple argument
+ --> $DIR/issue-22565-rust-call.rs:7:5
+ |
+LL | extern "rust-call" fn a();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: functions with the "rust-call" ABI must take a single non-self tuple argument
+ --> $DIR/issue-22565-rust-call.rs:10:5
+ |
+LL | extern "rust-call" fn b() {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+For more information about this error, try `rustc --explain E0277`.
// check-pass
//[opt] compile-flags: -Zmir-opt-level=3
-#![feature(unboxed_closures)]
+#![feature(unboxed_closures, tuple_trait)]
-extern "rust-call" fn foo<T>(_: T) {}
+extern "rust-call" fn foo<T: std::marker::Tuple>(_: T) {}
fn main() {
foo(());
+++ /dev/null
-// run-pass
-
-#![allow(stable_features)]
-#![allow(unused_variables)]
-
-// #45662
-
-#![feature(repr_align)]
-
-#[repr(align(16))]
-pub struct A(#[allow(unused_tuple_struct_fields)] i64);
-
-#[allow(improper_ctypes_definitions)]
-pub extern "C" fn foo(x: A) {}
-
-fn main() {
- foo(A(0));
-}
+++ /dev/null
-// run-pass
-// allows aligned custom discriminant enums to cast into other types
-// See the issue #92464 for more info
-#[allow(dead_code)]
-#[repr(align(8))]
-enum Aligned {
- Zero = 0,
- One = 1,
-}
-
-fn main() {
- let aligned = Aligned::Zero;
- let fo = aligned as u8;
- println!("foo {}", fo);
- assert_eq!(fo, 0);
- println!("{}", tou8(Aligned::Zero));
- assert_eq!(tou8(Aligned::Zero), 0);
-}
-
-#[inline(never)]
-fn tou8(al: Aligned) -> u8 {
- // Cast behind a function call so ConstProp does not see it
- // (so that we can test codegen).
- al as u8
-}
#[alloc_error_handler]
fn oom(
- info: &Layout, //~ ERROR argument should be `Layout`
-) -> () //~ ERROR return type should be `!`
+ info: &Layout, //~^ ERROR mismatched types
+) -> () //~^^ ERROR mismatched types
{
loop {}
}
-error: return type should be `!`
- --> $DIR/alloc-error-handler-bad-signature-1.rs:12:6
+error[E0308]: mismatched types
+ --> $DIR/alloc-error-handler-bad-signature-1.rs:10:1
|
-LL | ) -> ()
- | ^^
-
-error: argument should be `Layout`
- --> $DIR/alloc-error-handler-bad-signature-1.rs:11:11
+LL | #[alloc_error_handler]
+ | ---------------------- in this procedural macro expansion
+LL | fn oom(
+ | _^
+ | |_|
+ | ||
+LL | || info: &Layout,
+LL | || ) -> ()
+ | ||_______- arguments to this function are incorrect
+LL | | {
+LL | | loop {}
+LL | | }
+ | |__^ expected `&Layout`, found struct `Layout`
+ |
+note: function defined here
+ --> $DIR/alloc-error-handler-bad-signature-1.rs:10:4
|
+LL | fn oom(
+ | ^^^
LL | info: &Layout,
- | ^^^^^^^
+ | -------------
+ = note: this error originates in the attribute macro `alloc_error_handler` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+ --> $DIR/alloc-error-handler-bad-signature-1.rs:10:1
+ |
+LL | #[alloc_error_handler]
+ | ---------------------- in this procedural macro expansion
+LL | fn oom(
+ | _^
+ | |_|
+ | ||
+LL | || info: &Layout,
+LL | || ) -> ()
+ | ||_______^ expected `!`, found `()`
+LL | | {
+LL | | loop {}
+LL | | }
+ | |__- expected `!` because of return type
+ |
+ = note: expected type `!`
+ found unit type `()`
+ = note: this error originates in the attribute macro `alloc_error_handler` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0308`.
#[alloc_error_handler]
fn oom(
- info: Layout, //~ ERROR argument should be `Layout`
-) { //~ ERROR return type should be `!`
+ info: Layout, //~^ ERROR mismatched types
+) { //~^^ ERROR mismatched types
loop {}
}
-error: return type should be `!`
- --> $DIR/alloc-error-handler-bad-signature-2.rs:12:3
+error[E0308]: mismatched types
+ --> $DIR/alloc-error-handler-bad-signature-2.rs:10:1
|
-LL | ) {
- | ^
-
-error: argument should be `Layout`
- --> $DIR/alloc-error-handler-bad-signature-2.rs:11:11
+LL | #[alloc_error_handler]
+ | ---------------------- in this procedural macro expansion
+LL | fn oom(
+ | _^
+ | |_|
+ | ||
+LL | || info: Layout,
+LL | || ) {
+ | || -
+ | ||_|
+ | | arguments to this function are incorrect
+LL | | loop {}
+LL | | }
+ | |__^ expected struct `Layout`, found struct `core::alloc::Layout`
+ |
+ = note: struct `core::alloc::Layout` and struct `Layout` have similar names, but are actually distinct types
+note: struct `core::alloc::Layout` is defined in crate `core`
+ --> $SRC_DIR/core/src/alloc/layout.rs:LL:COL
+ |
+LL | pub struct Layout {
+ | ^^^^^^^^^^^^^^^^^
+note: struct `Layout` is defined in the current crate
+ --> $DIR/alloc-error-handler-bad-signature-2.rs:7:1
+ |
+LL | struct Layout;
+ | ^^^^^^^^^^^^^
+note: function defined here
+ --> $DIR/alloc-error-handler-bad-signature-2.rs:10:4
|
+LL | fn oom(
+ | ^^^
LL | info: Layout,
- | ^^^^^^
+ | ------------
+ = note: this error originates in the attribute macro `alloc_error_handler` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0308]: mismatched types
+ --> $DIR/alloc-error-handler-bad-signature-2.rs:10:1
+ |
+LL | #[alloc_error_handler]
+ | ---------------------- in this procedural macro expansion
+LL | fn oom(
+ | _^
+ | |_|
+ | ||
+LL | || info: Layout,
+LL | || ) {
+ | || ^
+ | ||_|
+ | | expected `!`, found `()`
+LL | | loop {}
+LL | | }
+ | |__- expected `!` because of return type
+ |
+ = note: expected type `!`
+ found unit type `()`
+ = note: this error originates in the attribute macro `alloc_error_handler` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0308`.
struct Layout;
#[alloc_error_handler]
-fn oom() -> ! { //~ ERROR function should have one argument
+fn oom() -> ! { //~ ERROR this function takes 0 arguments but 1 argument was supplied
loop {}
}
-error: function should have one argument
+error[E0061]: this function takes 0 arguments but 1 argument was supplied
--> $DIR/alloc-error-handler-bad-signature-3.rs:10:1
|
+LL | #[alloc_error_handler]
+ | ---------------------- in this procedural macro expansion
+LL | fn oom() -> ! {
+ | _-^^^^^^^^^^^^
+LL | | loop {}
+LL | | }
+ | |_- argument of type `core::alloc::Layout` unexpected
+ |
+note: function defined here
+ --> $DIR/alloc-error-handler-bad-signature-3.rs:10:4
+ |
LL | fn oom() -> ! {
- | ^^^^^^^^^^^^^
+ | ^^^
+ = note: this error originates in the attribute macro `alloc_error_handler` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: remove the extra argument
+ |
+LL | fn oom() -> !() {
+ | ++
error: aborting due to previous error
+For more information about this error, try `rustc --explain E0061`.
-error[E0268]: `break` outside of a loop
+error[E0268]: `break` outside of a loop or labeled block
--> $DIR/array-break-length.rs:3:17
|
LL | |_: [_; break]| {}
- | ^^^^^ cannot `break` outside of a loop
+ | ^^^^^ cannot `break` outside of a loop or labeled block
error[E0268]: `continue` outside of a loop
--> $DIR/array-break-length.rs:7:17
--- /dev/null
+// only-aarch64
+// run-pass
+// needs-asm-support
+
+// Test that we properly work around this LLVM issue:
+// https://github.com/llvm/llvm-project/issues/58384
+
+use std::arch::asm;
+
+fn main() {
+ let a: i32;
+ unsafe {
+ asm!("", inout("x0") 435 => a);
+ }
+ assert_eq!(a, 435);
+}
// needs-asm-support
// build-pass
-#![feature(no_core, lang_items, rustc_attrs, isa_attribute)]
+#![feature(no_core, lang_items, rustc_attrs)]
#![no_core]
#![crate_type = "rlib"]
+++ /dev/null
-// Test that inherent associated types work with
-// inherent_associated_types feature gate.
-
-#![feature(inherent_associated_types)]
-#![allow(incomplete_features)]
-
-struct Foo;
-
-impl Foo {
- type Bar = isize;
-}
-
-impl Foo {
- type Baz; //~ ERROR associated type in `impl` without body
-}
-
-fn main() {
- let x : Foo::Bar; //~ERROR ambiguous associated type
- x = 0isize;
-}
+++ /dev/null
-error: associated type in `impl` without body
- --> $DIR/assoc-inherent.rs:14:5
- |
-LL | type Baz;
- | ^^^^^^^^-
- | |
- | help: provide a definition for the type: `= <type>;`
-
-error[E0223]: ambiguous associated type
- --> $DIR/assoc-inherent.rs:18:13
- |
-LL | let x : Foo::Bar;
- | ^^^^^^^^ help: use fully-qualified syntax: `<Foo as Trait>::Bar`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0223`.
--- /dev/null
+#![feature(inherent_associated_types)]
+#![allow(incomplete_features)]
+
+struct Foo;
+
+impl Foo {
+ type Baz; //~ ERROR associated type in `impl` without body
+}
+
+fn main() {}
--- /dev/null
+error: associated type in `impl` without body
+ --> $DIR/assoc-inherent-no-body.rs:7:5
+ |
+LL | type Baz;
+ | ^^^^^^^^-
+ | |
+ | help: provide a definition for the type: `= <type>;`
+
+error: aborting due to previous error
+
--- /dev/null
+// check-pass
+#![feature(inherent_associated_types)]
+#![allow(incomplete_features)]
+
+struct Foo;
+
+impl Foo {
+ type Bar = isize;
+}
+
+fn main() {
+ let x: Foo::Bar;
+ x = 0isize;
+}
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: lifetime may not live long enough
- --> $DIR/project-fn-ret-invariant.rs:40:13
+ --> $DIR/project-fn-ret-invariant.rs:42:13
|
LL | fn baz<'a, 'b>(x: Type<'a>, y: Type<'b>) -> (Type<'a>, Type<'b>) {
| -- -- lifetime `'b` defined here
| |
| lifetime `'a` defined here
-LL | let f = foo; // <-- No consistent type can be inferred for `f` here.
-LL | let a = bar(f, x);
+...
+LL | let b = bar(f, y);
| ^^^^^^^^^ argument requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
- = note: requirement occurs because of a function pointer to `foo`
- = note: the function `foo` is invariant over the parameter `'a`
+ = note: requirement occurs because of the type `Type<'_>`, which makes the generic argument `'_` invariant
+ = note: the struct `Type<'a>` is invariant over the parameter `'a`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
help: `'a` and `'b` must be the same: replace one with the other
let f = foo; // <-- No consistent type can be inferred for `f` here.
let a = bar(f, x);
//[oneuse]~^ ERROR lifetime may not live long enough
- //[oneuse]~| ERROR lifetime may not live long enough
let b = bar(f, y);
+ //[oneuse]~^ ERROR lifetime may not live long enough
(a, b)
}
LL | assert_send(non_sync_with_method_call());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send`
|
- = help: the trait `Send` is not implemented for `dyn std::fmt::Write`
+ = help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `dyn std::fmt::Write`
note: future is not `Send` as this value is used across an await
--> $DIR/async-fn-nonsend.rs:46:14
|
--- /dev/null
+// check-fail
+// known-bug: #102682
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+use std::fmt::Debug;
+
+trait MyTrait<'a, 'b, T> where Self: 'a, T: Debug + Sized + 'b {
+ type MyAssoc;
+
+ async fn foo(&'a self, key: &'b T) -> Self::MyAssoc;
+}
+
+impl<'a, 'b, T: Debug + Sized + 'b, U: 'a> MyTrait<'a, 'b, T> for U {
+ type MyAssoc = (&'a U, &'b T);
+
+ async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) {
+ (self, key)
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
+ --> $DIR/async-associated-types.rs:19:43
+ |
+LL | async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) {
+ | ^^^^^^^^^^^^^^
+ |
+note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
+ --> $DIR/async-associated-types.rs:16:6
+ |
+LL | impl<'a, 'b, T: Debug + Sized + 'b, U: 'a> MyTrait<'a, 'b, T> for U {
+ | ^^
+note: ...so that the types are compatible
+ --> $DIR/async-associated-types.rs:19:43
+ |
+LL | async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) {
+ | ^^^^^^^^^^^^^^
+ = note: expected `(&'a U, &'b T)`
+ found `(&U, &T)`
+ = note: but, the lifetime must be valid for the static lifetime...
+note: ...so that the types are compatible
+ --> $DIR/async-associated-types.rs:19:43
+ |
+LL | async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) {
+ | ^^^^^^^^^^^^^^
+ = note: expected `MyTrait<'static, 'static, T>`
+ found `MyTrait<'_, '_, T>`
+
+error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting requirements
+ --> $DIR/async-associated-types.rs:19:43
+ |
+LL | async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) {
+ | ^^^^^^^^^^^^^^
+ |
+note: first, the lifetime cannot outlive the lifetime `'b` as defined here...
+ --> $DIR/async-associated-types.rs:16:10
+ |
+LL | impl<'a, 'b, T: Debug + Sized + 'b, U: 'a> MyTrait<'a, 'b, T> for U {
+ | ^^
+note: ...so that the types are compatible
+ --> $DIR/async-associated-types.rs:19:43
+ |
+LL | async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) {
+ | ^^^^^^^^^^^^^^
+ = note: expected `(&'a U, &'b T)`
+ found `(&U, &T)`
+ = note: but, the lifetime must be valid for the static lifetime...
+note: ...so that the types are compatible
+ --> $DIR/async-associated-types.rs:19:43
+ |
+LL | async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) {
+ | ^^^^^^^^^^^^^^
+ = note: expected `MyTrait<'static, 'static, T>`
+ found `MyTrait<'_, '_, T>`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0495`.
--- /dev/null
+// check-pass
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![feature(type_alias_impl_trait)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+
+trait MyTrait {
+ type Fut<'a>: Future<Output = i32>
+ where
+ Self: 'a;
+
+ fn foo<'a>(&'a self) -> Self::Fut<'a>;
+}
+
+impl MyTrait for i32 {
+ type Fut<'a> = impl Future<Output = i32> + 'a
+ where
+ Self: 'a;
+
+ fn foo<'a>(&'a self) -> Self::Fut<'a> {
+ async {
+ *self
+ }
+ }
+}
+
+fn main() {}
--- /dev/null
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+use std::pin::Pin;
+
+trait MyTrait {
+ fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>>;
+}
+
+impl MyTrait for i32 {
+ async fn foo(&self) -> i32 {
+ //~^ ERROR method `foo` has an incompatible type for trait
+ *self
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0053]: method `foo` has an incompatible type for trait
+ --> $DIR/async-example-desugared-boxed-in-trait.rs:15:28
+ |
+LL | async fn foo(&self) -> i32 {
+ | ^^^ expected struct `Pin`, found opaque type
+ |
+note: type in trait
+ --> $DIR/async-example-desugared-boxed-in-trait.rs:11:22
+ |
+LL | fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ = note: expected fn pointer `fn(&i32) -> Pin<Box<dyn Future<Output = i32>>>`
+ found fn pointer `fn(&i32) -> impl Future<Output = i32>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0053`.
--- /dev/null
+// check-pass
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+use std::pin::Pin;
+
+trait MyTrait {
+ async fn foo(&self) -> i32;
+}
+
+impl MyTrait for i32 {
+ // This will break once a PR that implements #102745 is merged
+ fn foo(&self) -> Pin<Box<dyn Future<Output = i32> + '_>> {
+ Box::pin(async {
+ *self
+ })
+ }
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+
+trait MyTrait {
+ fn foo(&self) -> impl Future<Output = i32> + '_;
+}
+
+impl MyTrait for i32 {
+ // This will break once a PR that implements #102745 is merged
+ async fn foo(&self) -> i32 {
+ *self
+ }
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+
+trait MyTrait {
+ async fn foo(&self) -> i32;
+}
+
+impl MyTrait for i32 {
+ // This will break once a PR that implements #102745 is merged
+ fn foo(&self) -> impl Future<Output = i32> + '_ {
+ async {
+ *self
+ }
+ }
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+trait MyTrait {
+ async fn foo(&self) -> i32;
+ async fn bar(&self) -> i32;
+}
+
+impl MyTrait for i32 {
+ async fn foo(&self) -> i32 {
+ *self
+ }
+
+ async fn bar(&self) -> i32 {
+ self.foo().await
+ }
+}
+
+fn main() {
+ let x = 5;
+ // Calling from non-async context
+ let _ = x.foo();
+ let _ = x.bar();
+ // Calling from async block in non-async context
+ async {
+ let _: i32 = x.foo().await;
+ let _: i32 = x.bar().await;
+ };
+}
--- /dev/null
+// check-fail
+// known-bug: #102682
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+use std::fmt::Debug;
+use std::hash::Hash;
+
+trait MyTrait<T, U> {
+ async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
+}
+
+impl<T, U> MyTrait<T, U> for (T, U) {
+ async fn foo(&self) -> &(T, U) {
+ self
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0311]: the parameter type `U` may not live long enough
+ --> $DIR/async-generics-and-bounds.rs:12:28
+ |
+LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
+ | ^^^^^^^
+ |
+note: the parameter type `U` must be valid for the anonymous lifetime as defined here...
+ --> $DIR/async-generics-and-bounds.rs:12:18
+ |
+LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
+ | ^
+note: ...so that the reference type `&(T, U)` does not outlive the data it points at
+ --> $DIR/async-generics-and-bounds.rs:12:28
+ |
+LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
+ | ^^^^^^^
+
+error[E0311]: the parameter type `T` may not live long enough
+ --> $DIR/async-generics-and-bounds.rs:12:28
+ |
+LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
+ | ^^^^^^^
+ |
+note: the parameter type `T` must be valid for the anonymous lifetime as defined here...
+ --> $DIR/async-generics-and-bounds.rs:12:18
+ |
+LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
+ | ^
+note: ...so that the reference type `&(T, U)` does not outlive the data it points at
+ --> $DIR/async-generics-and-bounds.rs:12:28
+ |
+LL | async fn foo(&self) -> &(T, U) where T: Debug + Sized, U: Hash;
+ | ^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0311`.
--- /dev/null
+// check-fail
+// known-bug: #102682
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+trait MyTrait<T, U> {
+ async fn foo(&self) -> &(T, U);
+}
+
+impl<T, U> MyTrait<T, U> for (T, U) {
+ async fn foo(&self) -> &(T, U) {
+ self
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0311]: the parameter type `U` may not live long enough
+ --> $DIR/async-generics.rs:9:28
+ |
+LL | async fn foo(&self) -> &(T, U);
+ | ^^^^^^^
+ |
+note: the parameter type `U` must be valid for the anonymous lifetime as defined here...
+ --> $DIR/async-generics.rs:9:18
+ |
+LL | async fn foo(&self) -> &(T, U);
+ | ^
+note: ...so that the reference type `&(T, U)` does not outlive the data it points at
+ --> $DIR/async-generics.rs:9:28
+ |
+LL | async fn foo(&self) -> &(T, U);
+ | ^^^^^^^
+
+error[E0311]: the parameter type `T` may not live long enough
+ --> $DIR/async-generics.rs:9:28
+ |
+LL | async fn foo(&self) -> &(T, U);
+ | ^^^^^^^
+ |
+note: the parameter type `T` must be valid for the anonymous lifetime as defined here...
+ --> $DIR/async-generics.rs:9:18
+ |
+LL | async fn foo(&self) -> &(T, U);
+ | ^
+note: ...so that the reference type `&(T, U)` does not outlive the data it points at
+ --> $DIR/async-generics.rs:9:28
+ |
+LL | async fn foo(&self) -> &(T, U);
+ | ^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0311`.
--- /dev/null
+// check-fail
+// known-bug: #102682
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+use std::fmt::Debug;
+
+trait MyTrait<'a, 'b, T> {
+ async fn foo(&'a self, key: &'b T) -> (&'a Self, &'b T) where T: Debug + Sized;
+}
+
+impl<'a, 'b, T, U> MyTrait<'a, 'b, T> for U {
+ async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) {
+ (self, key)
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0309]: the parameter type `Self` may not live long enough
+ --> $DIR/async-lifetimes-and-bounds.rs:11:43
+ |
+LL | async fn foo(&'a self, key: &'b T) -> (&'a Self, &'b T) where T: Debug + Sized;
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `Self: 'a`...
+ = note: ...so that the reference type `&'a Self` does not outlive the data it points at
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/async-lifetimes-and-bounds.rs:11:43
+ |
+LL | async fn foo(&'a self, key: &'b T) -> (&'a Self, &'b T) where T: Debug + Sized;
+ | ^^^^^^^^^^^^^^^^^ ...so that the reference type `&'b T` does not outlive the data it points at
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | trait MyTrait<'a, 'b, T: 'b> {
+ | ++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
--- /dev/null
+// check-fail
+// known-bug: #102682
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+trait MyTrait<'a, 'b, T> {
+ async fn foo(&'a self, key: &'b T) -> (&'a Self, &'b T);
+}
+
+impl<'a, 'b, T, U> MyTrait<'a, 'b, T> for U {
+ async fn foo(&'a self, key: &'b T) -> (&'a U, &'b T) {
+ (self, key)
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0309]: the parameter type `Self` may not live long enough
+ --> $DIR/async-lifetimes.rs:9:43
+ |
+LL | async fn foo(&'a self, key: &'b T) -> (&'a Self, &'b T);
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = help: consider adding an explicit lifetime bound `Self: 'a`...
+ = note: ...so that the reference type `&'a Self` does not outlive the data it points at
+
+error[E0309]: the parameter type `T` may not live long enough
+ --> $DIR/async-lifetimes.rs:9:43
+ |
+LL | async fn foo(&'a self, key: &'b T) -> (&'a Self, &'b T);
+ | ^^^^^^^^^^^^^^^^^ ...so that the reference type `&'b T` does not outlive the data it points at
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | trait MyTrait<'a, 'b, T: 'b> {
+ | ++++
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0309`.
--- /dev/null
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+trait MyTrait<T> {
+ async fn foo_recursive(&self, n: usize) -> T;
+}
+
+impl<T> MyTrait<T> for T where T: Copy {
+ async fn foo_recursive(&self, n: usize) -> T {
+ //~^ ERROR recursion in an `async fn` requires boxing
+ if n > 0 {
+ self.foo_recursive(n - 1).await
+ } else {
+ *self
+ }
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0733]: recursion in an `async fn` requires boxing
+ --> $DIR/async-recursive-generic.rs:11:48
+ |
+LL | async fn foo_recursive(&self, n: usize) -> T {
+ | ^ recursive `async fn`
+ |
+ = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
+ = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0733`.
--- /dev/null
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+trait MyTrait {
+ async fn foo_recursive(&self, n: usize) -> i32;
+}
+
+impl MyTrait for i32 {
+ async fn foo_recursive(&self, n: usize) -> i32 {
+ //~^ ERROR recursion in an `async fn` requires boxing
+ if n > 0 {
+ self.foo_recursive(n - 1).await
+ } else {
+ *self
+ }
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0733]: recursion in an `async fn` requires boxing
+ --> $DIR/async-recursive.rs:11:48
+ |
+LL | async fn foo_recursive(&self, n: usize) -> i32 {
+ | ^^^ recursive `async fn`
+ |
+ = note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
+ = note: consider using the `async_recursion` crate: https://crates.io/crates/async_recursion
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0733`.
--- /dev/null
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+trait MyTrait {
+ async fn foo(&self) -> i32;
+}
+
+impl MyTrait for i32 {
+ fn foo(&self) -> i32 {
+ //~^ ERROR: `i32` is not a future [E0277]
+ *self
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0277]: `i32` is not a future
+ --> $DIR/fn-not-async-err.rs:11:22
+ |
+LL | fn foo(&self) -> i32 {
+ | ^^^ `i32` is not a future
+ |
+ = help: the trait `Future` is not implemented for `i32`
+ = note: i32 must be a future or must implement `IntoFuture` to be awaited
+note: required by a bound in `MyTrait::foo::{opaque#0}`
+ --> $DIR/fn-not-async-err.rs:7:28
+ |
+LL | async fn foo(&self) -> i32;
+ | ^^^ required by this bound in `MyTrait::foo::{opaque#0}`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// edition: 2021
+
+#![feature(async_fn_in_trait)]
+#![allow(incomplete_features)]
+
+use std::future::Future;
+
+trait MyTrait {
+ async fn foo(&self) -> i32;
+}
+
+impl MyTrait for i32 {
+ fn foo(&self) -> impl Future<Output = i32> {
+ //~^ ERROR `impl Trait` only allowed in function and inherent method return types, not in `impl` method return [E0562]
+ async {
+ *self
+ }
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `impl` method return
+ --> $DIR/fn-not-async-err2.rs:13:22
+ |
+LL | fn foo(&self) -> impl Future<Output = i32> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+ = help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0562`.
--- /dev/null
+// edition: 2021
+
+use std::{
+ future::Future,
+ pin::Pin,
+ task::{Context, Poll, Waker},
+};
+
+pub struct StructAsync<F: Fn() -> Pin<Box<dyn Future<Output = ()>>>> {
+ pub callback: F,
+}
+
+impl<F> Future for StructAsync<F>
+where
+ F: Fn() -> Pin<Box<dyn Future<Output = ()>>>,
+{
+ type Output = ();
+
+ fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Self::Output> {
+ Poll::Pending
+ }
+}
+
+async fn callback() {}
+
+struct Runtime;
+
+fn waker() -> &'static Waker {
+ todo!()
+}
+
+impl Runtime {
+ #[track_caller]
+ pub fn block_on<F: Future>(&self, mut future: F) -> F::Output {
+ loop {
+ unsafe {
+ Pin::new_unchecked(&mut future).poll(&mut Context::from_waker(waker()));
+ }
+ }
+ }
+}
+
+fn main() {
+ Runtime.block_on(async {
+ StructAsync { callback }.await;
+ //~^ ERROR expected `fn() -> impl Future<Output = ()> {callback}` to be a fn item that returns `Pin<Box<(dyn Future<Output = ()> + 'static)>>`, but it returns `impl Future<Output = ()>`
+ //~| ERROR expected `fn() -> impl Future<Output = ()> {callback}` to be a fn item that returns `Pin<Box<(dyn Future<Output = ()> + 'static)>>`, but it returns `impl Future<Output = ()>`
+ //~| ERROR expected `fn() -> impl Future<Output = ()> {callback}` to be a fn item that returns `Pin<Box<(dyn Future<Output = ()> + 'static)>>`, but it returns `impl Future<Output = ()>`
+ });
+}
--- /dev/null
+error[E0271]: expected `fn() -> impl Future<Output = ()> {callback}` to be a fn item that returns `Pin<Box<(dyn Future<Output = ()> + 'static)>>`, but it returns `impl Future<Output = ()>`
+ --> $DIR/issue-98634.rs:45:23
+ |
+LL | StructAsync { callback }.await;
+ | ^^^^^^^^ expected struct `Pin`, found opaque type
+ |
+note: while checking the return type of the `async fn`
+ --> $DIR/issue-98634.rs:24:21
+ |
+LL | async fn callback() {}
+ | ^ checked the `Output` of this `async fn`, found opaque type
+ = note: expected struct `Pin<Box<(dyn Future<Output = ()> + 'static)>>`
+ found opaque type `impl Future<Output = ()>`
+note: required by a bound in `StructAsync`
+ --> $DIR/issue-98634.rs:9:35
+ |
+LL | pub struct StructAsync<F: Fn() -> Pin<Box<dyn Future<Output = ()>>>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `StructAsync`
+
+error[E0271]: expected `fn() -> impl Future<Output = ()> {callback}` to be a fn item that returns `Pin<Box<(dyn Future<Output = ()> + 'static)>>`, but it returns `impl Future<Output = ()>`
+ --> $DIR/issue-98634.rs:45:9
+ |
+LL | StructAsync { callback }.await;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Pin`, found opaque type
+ |
+note: while checking the return type of the `async fn`
+ --> $DIR/issue-98634.rs:24:21
+ |
+LL | async fn callback() {}
+ | ^ checked the `Output` of this `async fn`, found opaque type
+ = note: expected struct `Pin<Box<(dyn Future<Output = ()> + 'static)>>`
+ found opaque type `impl Future<Output = ()>`
+note: required by a bound in `StructAsync`
+ --> $DIR/issue-98634.rs:9:35
+ |
+LL | pub struct StructAsync<F: Fn() -> Pin<Box<dyn Future<Output = ()>>>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `StructAsync`
+
+error[E0271]: expected `fn() -> impl Future<Output = ()> {callback}` to be a fn item that returns `Pin<Box<(dyn Future<Output = ()> + 'static)>>`, but it returns `impl Future<Output = ()>`
+ --> $DIR/issue-98634.rs:45:33
+ |
+LL | StructAsync { callback }.await;
+ | ^^^^^^ expected struct `Pin`, found opaque type
+ |
+note: while checking the return type of the `async fn`
+ --> $DIR/issue-98634.rs:24:21
+ |
+LL | async fn callback() {}
+ | ^ checked the `Output` of this `async fn`, found opaque type
+ = note: expected struct `Pin<Box<(dyn Future<Output = ()> + 'static)>>`
+ found opaque type `impl Future<Output = ()>`
+note: required by a bound in `StructAsync`
+ --> $DIR/issue-98634.rs:9:35
+ |
+LL | pub struct StructAsync<F: Fn() -> Pin<Box<dyn Future<Output = ()>>>> {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `StructAsync`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0271`.
error[E0521]: borrowed data escapes outside of associated function
- --> $DIR/issue-72312.rs:12:24
+ --> $DIR/issue-72312.rs:12:9
|
LL | pub async fn start(&self) {
| -----
| `self` is a reference that is only valid in the associated function body
| let's call the lifetime of this reference `'1`
...
-LL | require_static(async move {
- | ________________________^
+LL | / require_static(async move {
LL | |
LL | |
LL | |
LL | | &self;
LL | | });
- | | ^
- | | |
- | |_________`self` escapes the associated function body here
- | argument requires that `'1` must outlive `'static`
+ | | ^
+ | | |
+ | |__________`self` escapes the associated function body here
+ | argument requires that `'1` must outlive `'static`
error: aborting due to previous error
+++ /dev/null
-// aux-build:attr-from-macro.rs
-// run-pass
-
-extern crate attr_from_macro;
-
-attr_from_macro::creator! {
- struct Foo;
- enum Bar;
- enum FooBar;
-}
-
-fn main() {
- // Checking the `repr(u32)` on the enum.
- assert_eq!(4, std::mem::size_of::<Bar>());
- // Checking the `repr(u16)` on the enum.
- assert_eq!(2, std::mem::size_of::<FooBar>());
-
- // Checking the Debug impl on the types.
- eprintln!("{:?} {:?} {:?}", Foo, Bar::A, FooBar::A);
-}
+++ /dev/null
-#[macro_export]
-macro_rules! creator {
- (struct $name1:ident; enum $name2:ident; enum $name3:ident;) => {
- #[derive(Debug)]
- pub struct $name1;
-
- #[derive(Debug)]
- #[repr(u32)]
- pub enum $name2 { A }
-
- #[derive(Debug)]
- #[repr(u16)]
- pub enum $name3 { A }
- }
-}
-#![feature(unboxed_closures)]
+#![feature(unboxed_closures, tuple_trait)]
// Tests that we can't assign to or mutably borrow upvars from `Fn`
// closures (issue #17780)
*x = 5;
}
-fn to_fn<A, F: Fn<A>>(f: F) -> F {
+fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F {
f
}
-fn to_fn_mut<A, F: FnMut<A>>(f: F) -> F {
+fn to_fn_mut<A: std::marker::Tuple, F: FnMut<A>>(f: F) -> F {
f
}
error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure
--> $DIR/borrow-immutable-upvar-mutation.rs:21:27
|
-LL | fn to_fn<A, F: Fn<A>>(f: F) -> F {
- | - change this to accept `FnMut` instead of `Fn`
+LL | fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F {
+ | - change this to accept `FnMut` instead of `Fn`
...
LL | let _f = to_fn(|| x = 42);
| ----- -- ^^^^^^ cannot assign
error[E0596]: cannot borrow `y` as mutable, as it is a captured variable in a `Fn` closure
--> $DIR/borrow-immutable-upvar-mutation.rs:24:31
|
-LL | fn to_fn<A, F: Fn<A>>(f: F) -> F {
- | - change this to accept `FnMut` instead of `Fn`
+LL | fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F {
+ | - change this to accept `FnMut` instead of `Fn`
...
LL | let _g = to_fn(|| set(&mut y));
| ----- -- ^^^^^^ cannot borrow as mutable
error[E0594]: cannot assign to `z`, as it is a captured variable in a `Fn` closure
--> $DIR/borrow-immutable-upvar-mutation.rs:29:22
|
-LL | fn to_fn<A, F: Fn<A>>(f: F) -> F {
- | - change this to accept `FnMut` instead of `Fn`
+LL | fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F {
+ | - change this to accept `FnMut` instead of `Fn`
...
LL | to_fn(|| z = 42);
| ----- -- ^^^^^^ cannot assign
error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure
--> $DIR/borrow-immutable-upvar-mutation.rs:36:32
|
-LL | fn to_fn<A, F: Fn<A>>(f: F) -> F {
- | - change this to accept `FnMut` instead of `Fn`
+LL | fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F {
+ | - change this to accept `FnMut` instead of `Fn`
...
LL | let _f = to_fn(move || x = 42);
| ----- ------- ^^^^^^ cannot assign
error[E0596]: cannot borrow `y` as mutable, as it is a captured variable in a `Fn` closure
--> $DIR/borrow-immutable-upvar-mutation.rs:39:36
|
-LL | fn to_fn<A, F: Fn<A>>(f: F) -> F {
- | - change this to accept `FnMut` instead of `Fn`
+LL | fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F {
+ | - change this to accept `FnMut` instead of `Fn`
...
LL | let _g = to_fn(move || set(&mut y));
| ----- ------- ^^^^^^ cannot borrow as mutable
error[E0594]: cannot assign to `z`, as it is a captured variable in a `Fn` closure
--> $DIR/borrow-immutable-upvar-mutation.rs:44:27
|
-LL | fn to_fn<A, F: Fn<A>>(f: F) -> F {
- | - change this to accept `FnMut` instead of `Fn`
+LL | fn to_fn<A: std::marker::Tuple, F: Fn<A>>(f: F) -> F {
+ | - change this to accept `FnMut` instead of `Fn`
...
LL | to_fn(move || z = 42);
| ----- ------- ^^^^^^ cannot assign
-#![feature(unboxed_closures)]
+#![feature(unboxed_closures, tuple_trait)]
-fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
-fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
+fn to_fn_mut<A:std::marker::Tuple,F:FnMut<A>>(f: F) -> F { f }
+fn to_fn_once<A:std::marker::Tuple,F:FnOnce<A>>(f: F) -> F { f }
pub fn main() {
let bar: Box<_> = Box::new(3);
--- /dev/null
+// edition:2021
+
+struct StructA {
+ b: StructB,
+}
+
+async fn spawn_blocking<T>(f: impl (Fn() -> T) + Send + Sync + 'static) -> T {
+ todo!()
+}
+
+impl StructA {
+ async fn foo(&self) {
+ let bar = self.b.bar().await;
+ spawn_blocking(move || {
+ //~^ ERROR borrowed data escapes outside of associated function
+ self.b;
+ //~^ ERROR cannot move out of `self.b`, as `self` is a captured variable in an `Fn` closure
+ })
+ .await;
+ }
+}
+
+struct StructB {}
+
+impl StructB {
+ async fn bar(&self) -> Option<u8> {
+ None
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0507]: cannot move out of `self.b`, as `self` is a captured variable in an `Fn` closure
+ --> $DIR/issue-103624.rs:16:13
+ |
+LL | async fn foo(&self) {
+ | ----- captured outer variable
+LL | let bar = self.b.bar().await;
+LL | spawn_blocking(move || {
+ | ------- captured by this `Fn` closure
+LL |
+LL | self.b;
+ | ^^^^^^ move occurs because `self.b` has type `StructB`, which does not implement the `Copy` trait
+
+error[E0521]: borrowed data escapes outside of associated function
+ --> $DIR/issue-103624.rs:14:9
+ |
+LL | async fn foo(&self) {
+ | -----
+ | |
+ | `self` is a reference that is only valid in the associated function body
+ | let's call the lifetime of this reference `'1`
+LL | let bar = self.b.bar().await;
+LL | / spawn_blocking(move || {
+LL | |
+LL | | self.b;
+LL | |
+LL | | })
+ | | ^
+ | | |
+ | |__________`self` escapes the associated function body here
+ | argument requires that `'1` must outlive `'static`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0507, E0521.
+For more information about an error, try `rustc --explain E0507`.
--- /dev/null
+#![feature(abi_efiapi)]
+
+fn efiapi(f: extern "efiapi" fn(usize, ...)) {
+ //~^ ERROR: C-variadic function must have a compatible calling convention, like `C` or `cdecl`
+ //~^^ ERROR: using calling conventions other than `C` or `cdecl` for varargs functions is unstable
+ f(22, 44);
+}
+fn sysv(f: extern "sysv64" fn(usize, ...)) {
+ //~^ ERROR: C-variadic function must have a compatible calling convention, like `C` or `cdecl`
+ //~^^ ERROR: using calling conventions other than `C` or `cdecl` for varargs functions is unstable
+ f(22, 44);
+}
+fn win(f: extern "win64" fn(usize, ...)) {
+ //~^ ERROR: C-variadic function must have a compatible calling convention, like `C` or `cdecl`
+ //~^^ ERROR: using calling conventions other than `C` or `cdecl` for varargs functions is unstable
+ f(22, 44);
+}
+
+fn main() {}
--- /dev/null
+error[E0658]: using calling conventions other than `C` or `cdecl` for varargs functions is unstable
+ --> $DIR/feature-gate-extended_varargs_abi_support.rs:3:14
+ |
+LL | fn efiapi(f: extern "efiapi" fn(usize, ...)) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #100189 <https://github.com/rust-lang/rust/issues/100189> for more information
+ = help: add `#![feature(extended_varargs_abi_support)]` to the crate attributes to enable
+
+error[E0045]: C-variadic function must have a compatible calling convention, like `C` or `cdecl`
+ --> $DIR/feature-gate-extended_varargs_abi_support.rs:3:14
+ |
+LL | fn efiapi(f: extern "efiapi" fn(usize, ...)) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention
+
+error[E0658]: using calling conventions other than `C` or `cdecl` for varargs functions is unstable
+ --> $DIR/feature-gate-extended_varargs_abi_support.rs:8:12
+ |
+LL | fn sysv(f: extern "sysv64" fn(usize, ...)) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #100189 <https://github.com/rust-lang/rust/issues/100189> for more information
+ = help: add `#![feature(extended_varargs_abi_support)]` to the crate attributes to enable
+
+error[E0045]: C-variadic function must have a compatible calling convention, like `C` or `cdecl`
+ --> $DIR/feature-gate-extended_varargs_abi_support.rs:8:12
+ |
+LL | fn sysv(f: extern "sysv64" fn(usize, ...)) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention
+
+error[E0658]: using calling conventions other than `C` or `cdecl` for varargs functions is unstable
+ --> $DIR/feature-gate-extended_varargs_abi_support.rs:13:11
+ |
+LL | fn win(f: extern "win64" fn(usize, ...)) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: see issue #100189 <https://github.com/rust-lang/rust/issues/100189> for more information
+ = help: add `#![feature(extended_varargs_abi_support)]` to the crate attributes to enable
+
+error[E0045]: C-variadic function must have a compatible calling convention, like `C` or `cdecl`
+ --> $DIR/feature-gate-extended_varargs_abi_support.rs:13:11
+ |
+LL | fn win(f: extern "win64" fn(usize, ...)) {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0045, E0658.
+For more information about an error, try `rustc --explain E0045`.
|
::: $SRC_DIR/core/src/ops/function.rs:LL:COL
|
-LL | pub trait Fn<Args>: FnMut<Args> {
- | ------------------------------- similarly named trait `Fn` defined here
+LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
+ | -------------------------------------- similarly named trait `Fn` defined here
|
help: a trait with a similar name exists
|
trait Sized { }
extern "stdcall" {
- fn printf(_: *const u8, ...); //~ ERROR: variadic function must have C or cdecl calling
+ fn printf(_: *const u8, ...);
+ //~^ ERROR: C-variadic function must have a compatible calling convention,
+ // like C, cdecl, win64, sysv64 or efiapi
}
extern "C" {
-error[E0045]: C-variadic function must have C or cdecl calling convention
+error[E0045]: C-variadic function must have a compatible calling convention, like `C` or `cdecl`
--> $DIR/variadic-ffi-1.rs:9:5
|
LL | fn printf(_: *const u8, ...);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadics require C or cdecl calling convention
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention
error[E0060]: this function takes at least 2 arguments but 0 arguments were supplied
- --> $DIR/variadic-ffi-1.rs:20:9
+ --> $DIR/variadic-ffi-1.rs:22:9
|
LL | foo();
| ^^^-- two arguments of type `isize` and `u8` are missing
|
note: function defined here
- --> $DIR/variadic-ffi-1.rs:13:8
+ --> $DIR/variadic-ffi-1.rs:15:8
|
LL | fn foo(f: isize, x: u8, ...);
| ^^^
| ~~~~~~~~~~~~~~~~~~~~~~~
error[E0060]: this function takes at least 2 arguments but 1 argument was supplied
- --> $DIR/variadic-ffi-1.rs:21:9
+ --> $DIR/variadic-ffi-1.rs:23:9
|
LL | foo(1);
| ^^^--- an argument of type `u8` is missing
|
note: function defined here
- --> $DIR/variadic-ffi-1.rs:13:8
+ --> $DIR/variadic-ffi-1.rs:15:8
|
LL | fn foo(f: isize, x: u8, ...);
| ^^^
| ~~~~~~~~~~~~~
error[E0308]: mismatched types
- --> $DIR/variadic-ffi-1.rs:23:56
+ --> $DIR/variadic-ffi-1.rs:25:56
|
LL | let x: unsafe extern "C" fn(f: isize, x: u8) = foo;
| ------------------------------------- ^^^ expected non-variadic fn, found variadic function
found fn item `unsafe extern "C" fn(_, _, ...) {foo}`
error[E0308]: mismatched types
- --> $DIR/variadic-ffi-1.rs:24:54
+ --> $DIR/variadic-ffi-1.rs:26:54
|
LL | let y: extern "C" fn(f: isize, x: u8, ...) = bar;
| ----------------------------------- ^^^ expected variadic fn, found non-variadic function
found fn item `extern "C" fn(_, _) {bar}`
error[E0617]: can't pass `f32` to variadic function
- --> $DIR/variadic-ffi-1.rs:26:19
+ --> $DIR/variadic-ffi-1.rs:28:19
|
LL | foo(1, 2, 3f32);
| ^^^^ help: cast the value to `c_double`: `3f32 as c_double`
error[E0617]: can't pass `bool` to variadic function
- --> $DIR/variadic-ffi-1.rs:27:19
+ --> $DIR/variadic-ffi-1.rs:29:19
|
LL | foo(1, 2, true);
| ^^^^ help: cast the value to `c_int`: `true as c_int`
error[E0617]: can't pass `i8` to variadic function
- --> $DIR/variadic-ffi-1.rs:28:19
+ --> $DIR/variadic-ffi-1.rs:30:19
|
LL | foo(1, 2, 1i8);
| ^^^ help: cast the value to `c_int`: `1i8 as c_int`
error[E0617]: can't pass `u8` to variadic function
- --> $DIR/variadic-ffi-1.rs:29:19
+ --> $DIR/variadic-ffi-1.rs:31:19
|
LL | foo(1, 2, 1u8);
| ^^^ help: cast the value to `c_uint`: `1u8 as c_uint`
error[E0617]: can't pass `i16` to variadic function
- --> $DIR/variadic-ffi-1.rs:30:19
+ --> $DIR/variadic-ffi-1.rs:32:19
|
LL | foo(1, 2, 1i16);
| ^^^^ help: cast the value to `c_int`: `1i16 as c_int`
error[E0617]: can't pass `u16` to variadic function
- --> $DIR/variadic-ffi-1.rs:31:19
+ --> $DIR/variadic-ffi-1.rs:33:19
|
LL | foo(1, 2, 1u16);
| ^^^^ help: cast the value to `c_uint`: `1u16 as c_uint`
// ignore-arm stdcall isn't supported
+#![feature(extended_varargs_abi_support)]
+#![feature(abi_efiapi)]
fn baz(f: extern "stdcall" fn(usize, ...)) {
- //~^ ERROR: variadic function must have C or cdecl calling convention
+ //~^ ERROR: C-variadic function must have a compatible calling convention,
+ // like C, cdecl, win64, sysv64 or efiapi
+ f(22, 44);
+}
+
+fn sysv(f: extern "sysv64" fn(usize, ...)) {
+ f(22, 44);
+}
+fn win(f: extern "win64" fn(usize, ...)) {
+ f(22, 44);
+}
+fn efiapi(f: extern "efiapi" fn(usize, ...)) {
f(22, 44);
}
-error[E0045]: C-variadic function must have C or cdecl calling convention
- --> $DIR/variadic-ffi-2.rs:3:11
+error[E0045]: C-variadic function must have a compatible calling convention, like `C`, `cdecl`, `win64`, `sysv64` or `efiapi`
+ --> $DIR/variadic-ffi-2.rs:5:11
|
LL | fn baz(f: extern "stdcall" fn(usize, ...)) {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadics require C or cdecl calling convention
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention
error: aborting due to previous error
-#![feature(unboxed_closures)]
+#![feature(unboxed_closures, tuple_trait)]
use std::io::Read;
-fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
+fn to_fn_once<A:std::marker::Tuple,F:FnOnce<A>>(f: F) -> F { f }
fn main() {
let x = 1;
-// check-fail
+// known-bug: unknown
+// FIXME(chalk): Chalk needs support for the Tuple trait
// compile-flags: -Z chalk
fn main() -> () {
let mut c = b;
c();
- b(); //~ ERROR
+ b(); // FIXME: reenable when this is fixed ~ ERROR
// FIXME(chalk): this doesn't quite work
/*
-error[E0382]: borrow of moved value: `b`
- --> $DIR/closure.rs:28:5
+error[E0277]: `()` is not a tuple
+ --> $DIR/closure.rs:7:5
+ |
+LL | t();
+ | ^^^ the trait `Tuple` is not implemented for `()`
+ |
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+ |
+LL | fn main() -> () where (): Tuple {
+ | +++++++++++++++
+
+error[E0277]: `()` is not a tuple
+ --> $DIR/closure.rs:13:5
+ |
+LL | b();
+ | ^^^ the trait `Tuple` is not implemented for `()`
+ |
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+ |
+LL | fn main() -> () where (): Tuple {
+ | +++++++++++++++
+
+error[E0277]: `()` is not a tuple
+ --> $DIR/closure.rs:17:5
+ |
+LL | c();
+ | ^^^ the trait `Tuple` is not implemented for `()`
+ |
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+ |
+LL | fn main() -> () where (): Tuple {
+ | +++++++++++++++
+
+error[E0277]: `()` is not a tuple
+ --> $DIR/closure.rs:18:5
|
-LL | let mut c = b;
- | - value moved here
-...
LL | b();
- | ^ value borrowed here after move
+ | ^^^ the trait `Tuple` is not implemented for `()`
+ |
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+ |
+LL | fn main() -> () where (): Tuple {
+ | +++++++++++++++
+
+error[E0277]: `()` is not a tuple
+ --> $DIR/closure.rs:24:5
+ |
+LL | b();
+ | ^^^ the trait `Tuple` is not implemented for `()`
+ |
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+ |
+LL | fn main() -> () where (): Tuple {
+ | +++++++++++++++
+
+error[E0277]: `()` is not a tuple
+ --> $DIR/closure.rs:28:5
+ |
+LL | c();
+ | ^^^ the trait `Tuple` is not implemented for `()`
+ |
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+ |
+LL | fn main() -> () where (): Tuple {
+ | +++++++++++++++
+
+error[E0277]: `()` is not a tuple
+ --> $DIR/closure.rs:29:5
|
-note: closure cannot be moved more than once as it is not `Copy` due to moving the variable `a` out of its environment
- --> $DIR/closure.rs:21:9
+LL | b(); // FIXME: reenable when this is fixed ~ ERROR
+ | ^^^ the trait `Tuple` is not implemented for `()`
|
-LL | a = 1;
- | ^
-help: consider mutably borrowing `b`
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
|
-LL | let mut c = &mut b;
- | ++++
+LL | fn main() -> () where (): Tuple {
+ | +++++++++++++++
-error: aborting due to previous error
+error: aborting due to 7 previous errors
-For more information about this error, try `rustc --explain E0382`.
+For more information about this error, try `rustc --explain E0277`.
-// check-pass
+// known-bug: unknown
+// FIXME(chalk): Chalk needs support for the Tuple trait
// compile-flags: -Z chalk
use std::fmt::Display;
--- /dev/null
+error: the type `&dyn Fn(i32) -> _` is not well-formed (chalk)
+ --> $DIR/trait-objects.rs:11:12
+ |
+LL | let f: &dyn Fn(i32) -> _ = &|x| x + x;
+ | ^^^^^^^^^^^^^^^^^
+
+error[E0277]: `(i32,)` is not a tuple
+ --> $DIR/trait-objects.rs:12:5
+ |
+LL | f(2);
+ | ^^^^ the trait `Tuple` is not implemented for `(i32,)`
+ |
+help: consider introducing a `where` clause, but there might be an alternative better way to express this requirement
+ |
+LL | fn main() where (i32,): Tuple {
+ | +++++++++++++++++++
+
+error[E0277]: expected a `Fn<(i32,)>` closure, found `dyn Fn(i32) -> i32`
+ --> $DIR/trait-objects.rs:12:5
+ |
+LL | f(2);
+ | ^^^^ expected an `Fn<(i32,)>` closure, found `dyn Fn(i32) -> i32`
+ |
+ = help: the trait `Fn<(i32,)>` is not implemented for `dyn Fn(i32) -> i32`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+// check-pass
+
+#![feature(closure_lifetime_binder)]
+
+fn main() {
+ let _ = for<'a> || -> () {
+ let _: &'a bool = &true;
+ };
+}
--- /dev/null
+// check-pass
+
+#![feature(closure_lifetime_binder)]
+#![feature(rustc_attrs)]
+
+#[rustc_regions]
+fn main() {
+ for<'a> || -> () { for<'c> |_: &'a ()| -> () {}; };
+}
--- /dev/null
+note: external requirements
+ --> $DIR/nested-closures-regions.rs:8:24
+ |
+LL | for<'a> || -> () { for<'c> |_: &'a ()| -> () {}; };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: main::{closure#0}::{closure#0} with closure substs [
+ i8,
+ extern "rust-call" fn((&(),)),
+ (),
+ ]
+ = note: late-bound region is '_#4r
+ = note: late-bound region is '_#2r
+ = note: number of external vids: 3
+ = note: where '_#1r: '_#2r
+ = note: where '_#2r: '_#1r
+
+note: no external requirements
+ --> $DIR/nested-closures-regions.rs:8:5
+ |
+LL | for<'a> || -> () { for<'c> |_: &'a ()| -> () {}; };
+ | ^^^^^^^^^^^^^^^^
+ |
+ = note: defining type: main::{closure#0} with closure substs [
+ i8,
+ extern "rust-call" fn(()),
+ (),
+ ]
+ = note: late-bound region is '_#2r
+
+note: no external requirements
+ --> $DIR/nested-closures-regions.rs:7:1
+ |
+LL | fn main() {
+ | ^^^^^^^^^
+ |
+ = note: defining type: main
+
--- /dev/null
+// check-pass
+
+#![feature(closure_lifetime_binder)]
+
+fn main() {
+ for<'a> || -> () { for<'c> |_: &'a ()| -> () {}; };
+}
LL | while |_: [_; continue]| {} {}
| ^^^^^^^^ cannot `continue` outside of a loop
-error[E0268]: `break` outside of a loop
+error[E0268]: `break` outside of a loop or labeled block
--> $DIR/closure-array-break-length.rs:6:19
|
LL | while |_: [_; break]| {} {}
- | ^^^^^ cannot `break` outside of a loop
+ | ^^^^^ cannot `break` outside of a loop or labeled block
error: aborting due to 3 previous errors
--- /dev/null
+// check-pass
+// Checks that we can infer a closure signature even if the `FnOnce` bound is
+// a supertrait of the obligations we have currently registered for the Ty var.
+
+pub trait Receive<T, E>: FnOnce(Result<T, E>) {
+ fn receive(self, res: Result<T, E>);
+}
+
+impl<T, E, F: FnOnce(Result<T, E>)> Receive<T, E> for F {
+ fn receive(self, res: Result<T, E>) {
+ self(res)
+ }
+}
+
+pub trait Async<T, E> {
+ fn receive<F: Receive<T, E>>(self, f: F);
+}
+
+impl<T, E> Async<T, E> for Result<T, E> {
+ fn receive<F: Receive<T, E>>(self, f: F) {
+ f(self)
+ }
+}
+
+pub fn main() {
+ Ok::<u32, ()>(123).receive(|res| {
+ res.unwrap();
+ });
+}
|
::: $SRC_DIR/core/src/ops/function.rs:LL:COL
|
-LL | pub trait Fn<Args>: FnMut<Args> {
- | ------------------------------- similarly named trait `Fn` defined here
+LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
+ | -------------------------------------- similarly named trait `Fn` defined here
|
help: a trait with a similar name exists
|
--- /dev/null
+// check-pass
+
+pub trait Fn0: Fn(i32) -> Self::Out {
+ type Out;
+}
+
+impl<F: Fn(i32) -> ()> Fn0 for F {
+ type Out = ();
+}
+
+pub fn closure_typer(_: impl Fn0) {}
+
+fn main() {
+ closure_typer(move |x| {
+ let _: i64 = x.into();
+ });
+}
--- /dev/null
+// check-fail
+fn f(_: &i32) {}
+
+fn main() {
+ let x = Box::new(1i32);
+
+ f(&x);
+ f(&(x));
+ f(&{x});
+ //~^ ERROR mismatched types
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/coerce-block-tail-26978.rs:9:9
+ |
+LL | f(&{x});
+ | ^ expected `i32`, found struct `Box`
+ |
+ = note: expected type `i32`
+ found struct `Box<i32>`
+help: consider unboxing the value
+ |
+LL | f(&{*x});
+ | +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// check-fail
+use std::ops::Deref;
+
+fn main() {
+ fn save(who: &str) {
+ println!("I'll save you, {}!", who);
+ }
+
+ struct Madoka;
+
+ impl Deref for Madoka {
+ type Target = str;
+ fn deref(&self) -> &Self::Target {
+ "Madoka"
+ }
+ }
+
+ save(&{ Madoka });
+
+ fn reset(how: &u32) {
+ println!("Reset {} times", how);
+ }
+
+ struct Homura;
+
+ impl Deref for Homura {
+ type Target = u32;
+ fn deref(&self) -> &Self::Target {
+ &42
+ }
+ }
+
+ reset(&{ Homura });
+ //~^ ERROR mismatched types
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/coerce-block-tail-57749.rs:33:14
+ |
+LL | reset(&{ Homura });
+ | ^^^^^^ expected `u32`, found struct `Homura`
+ |
+help: consider dereferencing the type
+ |
+LL | reset(&{ *Homura });
+ | +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// check-fail
+// edition:2018
+fn _consume_reference<T: ?Sized>(_: &T) {}
+
+async fn _foo() {
+ _consume_reference::<i32>(&Box::new(7_i32));
+ _consume_reference::<i32>(&async { Box::new(7_i32) }.await);
+ //~^ ERROR mismatched types
+ _consume_reference::<[i32]>(&vec![7_i32]);
+ _consume_reference::<[i32]>(&async { vec![7_i32] }.await);
+}
+
+fn main() { }
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/coerce-block-tail-83783.rs:7:32
+ |
+LL | _consume_reference::<i32>(&async { Box::new(7_i32) }.await);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found struct `Box`
+ |
+ = note: expected type `i32`
+ found struct `Box<i32>`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// check-fail
+fn f(_: &[i32]) {}
+
+fn main() {
+ f(&Box::new([1, 2]));
+ //~^ ERROR mismatched types
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/coerce-block-tail-83850.rs:5:7
+ |
+LL | f(&Box::new([1, 2]));
+ | - ^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found struct `Box`
+ | |
+ | arguments to this function are incorrect
+ |
+ = note: expected reference `&[i32]`
+ found reference `&Box<[{integer}; 2]>`
+note: function defined here
+ --> $DIR/coerce-block-tail-83850.rs:2:4
+ |
+LL | fn f(_: &[i32]) {}
+ | ^ ---------
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// check-fail
+fn main() {
+ let _: &str = & { String::from("hahah")};
+ let _: &i32 = & { Box::new(1i32) };
+ //~^ ERROR mismatched types
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/coerce-block-tail.rs:4:23
+ |
+LL | let _: &i32 = & { Box::new(1i32) };
+ | ^^^^^^^^^^^^^^ expected `i32`, found struct `Box`
+ |
+ = note: expected type `i32`
+ found struct `Box<i32>`
+help: consider unboxing the value
+ |
+LL | let _: &i32 = & { *Box::new(1i32) };
+ | +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+// check-pass
+#![feature(coerce_unsized, unsize)]
+
+use std::marker::Unsize;
+use std::ops::CoerceUnsized;
+
+struct Foo<T: ?Sized>(Box<T>);
+
+impl<T> CoerceUnsized<Foo<dyn Baz>> for Foo<T> where T: Unsize<dyn Baz> {}
+
+struct Bar;
+
+trait Baz {}
+
+impl Baz for Bar {}
+
+fn main() {
+ let foo = Foo(Box::new(Bar));
+ let foobar: Foo<Bar> = foo;
+}
|
LL | unsafe impl MySafeTrait for Foo {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: remove `unsafe` from this trait implementation
+ |
+LL - unsafe impl MySafeTrait for Foo {}
+LL + impl MySafeTrait for Foo {}
+ |
error[E0200]: the trait `MyUnsafeTrait` requires an `unsafe impl` declaration
--> $DIR/coherence-default-trait-impl.rs:13:1
|
LL | impl MyUnsafeTrait for Foo {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the trait `MyUnsafeTrait` enforces invariants that the compiler can't check. Review the trait documentation and make sure this implementation upholds those invariants before adding the `unsafe` keyword
+help: add `unsafe` to this trait implementation
+ |
+LL | unsafe impl MyUnsafeTrait for Foo {}
+ | ++++++
error: aborting due to 2 previous errors
--- /dev/null
+#![feature(rustc_attrs)]
+
+#[rustc_strict_coherence]
+trait Foo {}
+//~^ ERROR to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled
+
+fn main() {}
--- /dev/null
+error: to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled
+ --> $DIR/strict-coherence-needs-negative-coherence.rs:4:1
+ |
+LL | #[rustc_strict_coherence]
+ | ------------------------- due to this attribute
+LL | trait Foo {}
+ | ^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// Check that the arguments provided through `// compile-flags` are added last to the command line
+// in UI tests. To ensure that we invoke rustc with a flag that expects an argument withut actually
+// providing it. If the compile-flags are not last, the test will fail as rustc will interpret the
+// next flag as the argument of this flag.
+//
+// compile-flags: --cap-lints
+// error-pattern: Argument to option 'cap-lints' missing
--- /dev/null
+error: Argument to option 'cap-lints' missing
+
--- /dev/null
+// compile-flags: -Z ui-testing=no
+
+// Line number < 10
+type A = B; //~ ERROR
+
+// Line number >=10, <100
+type C = D; //~ ERROR
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+// Line num >=100
+type E = F; //~ ERROR
+
+fn main() {}
--- /dev/null
+error[E0412]: cannot find type `B` in this scope
+ --> $DIR/ui-testing-optout.rs:4:10
+ |
+4 | type A = B;
+ | ^ not found in this scope
+
+error[E0412]: cannot find type `D` in this scope
+ --> $DIR/ui-testing-optout.rs:7:10
+ |
+4 | type A = B;
+ | ----------- similarly named type alias `A` defined here
+...
+7 | type C = D;
+ | ^ help: a type alias with a similar name exists: `A`
+
+error[E0412]: cannot find type `F` in this scope
+ --> $DIR/ui-testing-optout.rs:92:10
+ |
+4 | type A = B;
+ | ----------- similarly named type alias `A` defined here
+...
+92 | type E = F;
+ | ^ help: a type alias with a similar name exists: `A`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0412`.
trait Trait {}
impl dyn Trait { fn existing() {} }
-// FIXME: Should be a error for edition > 2015
+// FIXME: Should be an error for edition > 2015
#[cfg_accessible(Trait::existing)] //~ ERROR not sure
const A: bool = true;
#[cfg_accessible(Trait::unresolved)] //~ ERROR not sure
--- /dev/null
+// check-pass
+#![crate_type = "lib"]
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+pub trait MyIterator {
+ type Output;
+}
+
+pub trait Foo {
+ const ABC: usize;
+}
+
+pub struct IteratorStruct<const N: usize>{
+
+}
+
+pub struct Bar<const N: usize> {
+ pub data: [usize; N]
+}
+
+impl<const N: usize> MyIterator for IteratorStruct<N> {
+ type Output = Bar<N>;
+}
+
+pub fn test1<T: Foo>() -> impl MyIterator<Output = Bar<{T::ABC}>> where [(); T::ABC]: Sized {
+ IteratorStruct::<{T::ABC}>{}
+}
+
+pub trait Baz<const N: usize>{}
+impl<const N: usize> Baz<N> for Bar<N> {}
+pub fn test2<T: Foo>() -> impl MyIterator<Output = impl Baz<{ T::ABC }>> where [(); T::ABC]: Sized {
+ IteratorStruct::<{T::ABC}>{}
+}
--> $DIR/issue-82956.rs:25:24
|
LL | let mut iter = IntoIter::new(self);
- | ^^^^^^^^ not found in this scope
+ | ^^^^^^^^ use of undeclared type `IntoIter`
|
help: consider importing one of these items
|
--- /dev/null
+// build-pass
+
+#![feature(const_fn_trait_ref_impls)]
+#![feature(fn_traits)]
+#![feature(unboxed_closures)]
+#![feature(const_trait_impl)]
+#![feature(const_mut_refs)]
+#![feature(const_cmp)]
+#![feature(const_refs_to_cell)]
+
+use std::marker::Destruct;
+
+const fn tester_fn<T>(f: T) -> T::Output
+where
+ T: ~const Fn<()> + ~const Destruct,
+{
+ f()
+}
+
+const fn tester_fn_mut<T>(mut f: T) -> T::Output
+where
+ T: ~const FnMut<()> + ~const Destruct,
+{
+ f()
+}
+
+const fn tester_fn_once<T>(f: T) -> T::Output
+where
+ T: ~const FnOnce<()>,
+{
+ f()
+}
+
+const fn test_fn<T>(mut f: T) -> (T::Output, T::Output, T::Output)
+where
+ T: ~const Fn<()> + ~const Destruct,
+{
+ (
+ // impl<A: Tuple, F: ~const Fn + ?Sized> const Fn<A> for &F
+ tester_fn(&f),
+ // impl<A: Tuple, F: ~const Fn + ?Sized> const FnMut<A> for &F
+ tester_fn_mut(&f),
+ // impl<A: Tuple, F: ~const Fn + ?Sized> const FnOnce<A> for &F
+ tester_fn_once(&f),
+ )
+}
+
+const fn test_fn_mut<T>(mut f: T) -> (T::Output, T::Output)
+where
+ T: ~const FnMut<()> + ~const Destruct,
+{
+ (
+ // impl<A: Tuple, F: ~const FnMut + ?Sized> const FnMut<A> for &mut F
+ tester_fn_mut(&mut f),
+ // impl<A: Tuple, F: ~const FnMut + ?Sized> const FnOnce<A> for &mut F
+ tester_fn_once(&mut f),
+ )
+}
+const fn test(i: i32) -> i32 {
+ i + 1
+}
+
+const fn main() {
+ const fn one() -> i32 {
+ 1
+ };
+ const fn two() -> i32 {
+ 2
+ };
+
+ // FIXME(const_cmp_tuple)
+ let test_one = test_fn(one);
+ assert!(test_one.0 == 1);
+ assert!(test_one.1 == 1);
+ assert!(test_one.2 == 1);
+
+ let test_two = test_fn_mut(two);
+ assert!(test_two.0 == 1);
+ assert!(test_two.1 == 1);
+}
impl VTable {
pub fn new<T>() -> &'static Self {
const {
- //~^ ERROR the parameter type `T` may not live long enough
- //~| ERROR the parameter type `T` may not live long enough
&VTable {
layout: Layout::new::<T>(),
type_id: TypeId::of::<T>(),
+ //~^ ERROR the parameter type `T` may not live long enough
+ //~| ERROR the parameter type `T` may not live long enough
drop_in_place: unsafe {
transmute::<unsafe fn(*mut T), unsafe fn(*mut ())>(drop_in_place::<T>)
},
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/issue-102117.rs:16:9
+ --> $DIR/issue-102117.rs:19:26
|
-LL | / const {
-LL | |
-LL | |
-LL | | &VTable {
-... |
-LL | | }
-LL | | }
- | |_________^ ...so that the type `T` will meet its required lifetime bounds
+LL | type_id: TypeId::of::<T>(),
+ | ^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
| +++++++++
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/issue-102117.rs:16:9
+ --> $DIR/issue-102117.rs:19:26
|
-LL | / const {
-LL | |
-LL | |
-LL | | &VTable {
-... |
-LL | | }
-LL | | }
- | |_________^ ...so that the type `T` will meet its required lifetime bounds
+LL | type_id: TypeId::of::<T>(),
+ | ^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
--- /dev/null
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+struct S<const S: (), const S: S = { S }>;
+//~^ ERROR the name `S` is already used for a generic parameter in this item's generic parameters
+//~| ERROR missing generics for struct `S`
+//~| ERROR cycle detected when computing type of `S::S`
+//~| ERROR cycle detected when computing type of `S`
+
+fn main() {}
--- /dev/null
+error[E0403]: the name `S` is already used for a generic parameter in this item's generic parameters
+ --> $DIR/issue-103790.rs:4:29
+ |
+LL | struct S<const S: (), const S: S = { S }>;
+ | - ^ already used
+ | |
+ | first use of `S`
+
+error[E0107]: missing generics for struct `S`
+ --> $DIR/issue-103790.rs:4:32
+ |
+LL | struct S<const S: (), const S: S = { S }>;
+ | ^ expected at least 1 generic argument
+ |
+note: struct defined here, with at least 1 generic parameter: `S`
+ --> $DIR/issue-103790.rs:4:8
+ |
+LL | struct S<const S: (), const S: S = { S }>;
+ | ^ -----------
+help: add missing generic argument
+ |
+LL | struct S<const S: (), const S: S<S> = { S }>;
+ | ~~~~
+
+error[E0391]: cycle detected when computing type of `S::S`
+ --> $DIR/issue-103790.rs:4:32
+ |
+LL | struct S<const S: (), const S: S = { S }>;
+ | ^
+ |
+ = note: ...which immediately requires computing type of `S::S` again
+note: cycle used when computing type of `S`
+ --> $DIR/issue-103790.rs:4:1
+ |
+LL | struct S<const S: (), const S: S = { S }>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0391]: cycle detected when computing type of `S`
+ --> $DIR/issue-103790.rs:4:1
+ |
+LL | struct S<const S: (), const S: S = { S }>;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+note: ...which requires computing type of `S::S`...
+ --> $DIR/issue-103790.rs:4:32
+ |
+LL | struct S<const S: (), const S: S = { S }>;
+ | ^
+ = note: ...which again requires computing type of `S`, completing the cycle
+note: cycle used when collecting item types in top-level module
+ --> $DIR/issue-103790.rs:1:1
+ |
+LL | / #![feature(generic_const_exprs)]
+LL | | #![allow(incomplete_features)]
+LL | |
+LL | | struct S<const S: (), const S: S = { S }>;
+... |
+LL | |
+LL | | fn main() {}
+ | |____________^
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0107, E0391, E0403.
+For more information about an error, try `rustc --explain E0107`.
--- /dev/null
+// check-pass
+const _: () = core::mem::forget(Box::<u32>::default);
+const _: () = core::mem::forget(|| Box::<u32>::default());
+
+fn main() {}
--- /dev/null
+const ARR_LEN: usize = Tt::const_val::<[i8; 123]>();
+//~^ ERROR E0790
+
+trait Tt {
+ const fn const_val<T: Sized>() -> usize {
+ //~^ ERROR functions in traits cannot be declared const
+ core::mem::size_of::<T>()
+ }
+}
+
+fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] {
+ //~^ ERROR evaluation of constant value failed
+ //~| ERROR evaluation of constant value failed
+ z
+}
+
+fn main() {
+ let _ = f([1f32; ARR_LEN]);
+}
--- /dev/null
+error[E0379]: functions in traits cannot be declared const
+ --> $DIR/issue-54954.rs:5:5
+ |
+LL | const fn const_val<T: Sized>() -> usize {
+ | ^^^^^ functions in traits cannot be const
+
+error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
+ --> $DIR/issue-54954.rs:1:24
+ |
+LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot call associated function of trait
+...
+LL | / const fn const_val<T: Sized>() -> usize {
+LL | |
+LL | | core::mem::size_of::<T>()
+LL | | }
+ | |_____- `Tt::const_val` defined here
+
+error[E0080]: evaluation of constant value failed
+ --> $DIR/issue-54954.rs:11:15
+ |
+LL | fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] {
+ | ^^^^^^^ referenced constant has errors
+
+error[E0080]: evaluation of constant value failed
+ --> $DIR/issue-54954.rs:11:34
+ |
+LL | fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] {
+ | ^^^^^^^ referenced constant has errors
+
+error: aborting due to 4 previous errors
+
+Some errors have detailed explanations: E0080, E0379, E0790.
+For more information about an error, try `rustc --explain E0080`.
--> $DIR/issue-31997-1.rs:20:19
|
LL | let mut map = HashMap::new();
- | ^^^^^^^ not found in this scope
+ | ^^^^^^^ use of undeclared type `HashMap`
|
help: consider importing this struct
|
#[derive(Debug)]
pub struct Whatever {
pub field0: (),
- field1: (), //~ ERROR fields `field1`, `field2`, `field3` and `field4` are never read
+ field1: (), //~ ERROR fields `field1`, `field2`, `field3`, and `field4` are never read
field2: (),
field3: (),
field4: (),
-error: fields `field1`, `field2`, `field3` and `field4` are never read
+error: fields `field1`, `field2`, `field3`, and `field4` are never read
--> $DIR/clone-debug-dead-code-in-the-same-struct.rs:6:5
|
LL | pub struct Whatever {
--- /dev/null
+#![allow(unused_variables)]
+use std::fs::File;
+
+fn main() {
+ if Err(err) = File::open("hello.txt") {
+ //~^ ERROR: cannot find value `err` in this scope
+ //~| ERROR: mismatched types
+ }
+}
--- /dev/null
+error[E0425]: cannot find value `err` in this scope
+ --> $DIR/issue-103909.rs:5:12
+ |
+LL | if Err(err) = File::open("hello.txt") {
+ | ^^^ not found in this scope
+ |
+help: you might have meant to use pattern matching
+ |
+LL | if let Err(err) = File::open("hello.txt") {
+ | +++
+
+error[E0308]: mismatched types
+ --> $DIR/issue-103909.rs:5:8
+ |
+LL | if Err(err) = File::open("hello.txt") {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0425.
+For more information about an error, try `rustc --explain E0308`.
LL | | fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
LL | | }
| |_^
+ |
+ = note: the trait `Drop` enforces invariants that the compiler can't check. Review the trait documentation and make sure this implementation upholds those invariants before adding the `unsafe` keyword
+help: add `unsafe` to this trait implementation
+ |
+LL | unsafe impl<#[may_dangle] A, B: fmt::Debug> Drop for Pt<A, B> {
+ | ++++++
error[E0569]: requires an `unsafe impl` declaration due to `#[may_dangle]` attribute
--> $DIR/dropck-eyepatch-implies-unsafe-impl.rs:27:1
LL | | fn drop(&mut self) { println!("drop {} {:?}", self.0, self.2); }
LL | | }
| |_^
+ |
+ = note: the trait `Drop` enforces invariants that the compiler can't check. Review the trait documentation and make sure this implementation upholds those invariants before adding the `unsafe` keyword
+help: add `unsafe` to this trait implementation
+ |
+LL | unsafe impl<#[may_dangle] 'a, 'b, B: fmt::Debug> Drop for Pr<'a, 'b, B> {
+ | ++++++
error: aborting due to 2 previous errors
--- /dev/null
+// This test is a minimal version of an ICE in the dropck-eyepatch tests
+// found in the fix for #54943.
+
+// check-pass
+
+fn foo<T>(_t: T) {
+}
+
+fn main() {
+ struct A<'a, B: 'a>(&'a B);
+ let (a1, a2): (String, A<_>) = (String::from("auto"), A(&"this"));
+ foo((a1, a2));
+}
--- /dev/null
+// This test is a minimal version of an ICE in the dropck-eyepatch tests
+// found in the fix for #54943. In particular, this test is in unreachable
+// code as the initial fix for this ICE only worked if the code was reachable.
+
+// check-pass
+
+fn foo<T>(_t: T) {
+}
+
+fn main() {
+ return;
+
+ struct A<'a, B: 'a>(&'a B);
+ let (a1, a2): (String, A<_>) = (String::from("auto"), A(&"this"));
+ foo((a1, a2));
+}
--- /dev/null
+use std::fmt::Debug;
+
+fn make_dyn_star() {
+ let i = 42usize;
+ let dyn_i: dyn* Debug = i as dyn* Debug;
+ //~^ ERROR casting `usize` as `dyn* Debug` is invalid
+ //~| ERROR dyn* trait objects are unstable
+ //~| ERROR dyn* trait objects are unstable
+}
+
+fn main() {
+ make_dyn_star();
+}
--- /dev/null
+error[E0658]: dyn* trait objects are unstable
+ --> $DIR/no-explicit-dyn-star-cast.rs:5:16
+ |
+LL | let dyn_i: dyn* Debug = i as dyn* Debug;
+ | ^^^^^^^^^^
+ |
+ = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+ = help: add `#![feature(dyn_star)]` to the crate attributes to enable
+
+error[E0658]: dyn* trait objects are unstable
+ --> $DIR/no-explicit-dyn-star-cast.rs:5:34
+ |
+LL | let dyn_i: dyn* Debug = i as dyn* Debug;
+ | ^^^^^^^^^^
+ |
+ = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+ = help: add `#![feature(dyn_star)]` to the crate attributes to enable
+
+error[E0606]: casting `usize` as `dyn* Debug` is invalid
+ --> $DIR/no-explicit-dyn-star-cast.rs:5:29
+ |
+LL | let dyn_i: dyn* Debug = i as dyn* Debug;
+ | ^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0606, E0658.
+For more information about an error, try `rustc --explain E0606`.
--- /dev/null
+// aux-build:dyn-star-foreign.rs
+
+extern crate dyn_star_foreign;
+
+fn main() {
+ dyn_star_foreign::require_dyn_star_display(1usize as _);
+ //~^ ERROR casting `usize` as `dyn* std::fmt::Display` is invalid
+}
--- /dev/null
+error[E0606]: casting `usize` as `dyn* std::fmt::Display` is invalid
+ --> $DIR/no-explicit-dyn-star.rs:6:48
+ |
+LL | dyn_star_foreign::require_dyn_star_display(1usize as _);
+ | ^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0606`.
-error[E0045]: C-variadic function must have C or cdecl calling convention
+error[E0045]: C-variadic function must have a compatible calling convention, like `C` or `cdecl`
--> $DIR/E0045.rs:1:17
|
LL | extern "Rust" { fn foo(x: u8, ...); }
- | ^^^^^^^^^^^^^^^^^^^ C-variadics require C or cdecl calling convention
+ | ^^^^^^^^^^^^^^^^^^^ C-variadic function must have a compatible calling convention
error: aborting due to previous error
-error[E0059]: cannot use call notation; the first type parameter for the function trait is neither a tuple nor unit
- --> $DIR/E0059.rs:3:41
+error[E0059]: type parameter to bare `Fn` trait must be a tuple
+ --> $DIR/E0059.rs:3:11
|
LL | fn foo<F: Fn<i32>>(f: F) -> F::Output { f(3) }
- | ^^^^
+ | ^^^^^^^ the trait `Tuple` is not implemented for `i32`
+ |
+note: required by a bound in `Fn`
+ --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+ |
+LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
+ | ^^^^^ required by this bound in `Fn`
error: aborting due to previous error
| -- `-1` assigned here
LL |
LL | Second = -2,
- | ----------- discriminant for `Last` incremented from this startpoint (`Second` + 1 variant later => `Last` = -1)
+ | ------ discriminant for `Last` incremented from this startpoint (`Second` + 1 variant later => `Last` = -1)
LL |
LL | Last,
| ---- `-1` assigned here
| - `0` assigned here
LL |
LL | V5 = -2,
- | ------- discriminant for `V7` incremented from this startpoint (`V5` + 2 variants later => `V7` = 0)
+ | -- discriminant for `V7` incremented from this startpoint (`V5` + 2 variants later => `V7` = 0)
...
LL | V7,
| -- `0` assigned here
| -- `-2` assigned here
...
LL | V8 = -3,
- | ------- discriminant for `V9` incremented from this startpoint (`V8` + 1 variant later => `V9` = -2)
+ | -- discriminant for `V9` incremented from this startpoint (`V8` + 1 variant later => `V9` = -2)
LL |
LL | V9,
| -- `-2` assigned here
|
LL | unsafe impl Bar for Foo { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: remove `unsafe` from this trait implementation
+ |
+LL - unsafe impl Bar for Foo { }
+LL + impl Bar for Foo { }
+ |
error: aborting due to previous error
|
LL | impl Bar for Foo { }
| ^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the trait `Bar` enforces invariants that the compiler can't check. Review the trait documentation and make sure this implementation upholds those invariants before adding the `unsafe` keyword
+help: add `unsafe` to this trait implementation
+ |
+LL | unsafe impl Bar for Foo { }
+ | ++++++
error: aborting due to previous error
-error[E0268]: `break` outside of a loop
+error[E0268]: `break` outside of a loop or labeled block
--> $DIR/E0268.rs:2:5
|
LL | break;
- | ^^^^^ cannot `break` outside of a loop
+ | ^^^^^ cannot `break` outside of a loop or labeled block
error: aborting due to previous error
fn main() {
- let x = "hello".chars().rev().collect(); //~ ERROR E0282
+ let x = "hello".chars().rev().collect();
+ //~^ ERROR E0282
}
W: Fn()>
(y: T) { //~ ERROR E0401
}
- bfnr(x); //~ ERROR type annotations needed
+ bfnr(x);
+ //~^ ERROR type annotations needed
+ //~| ERROR type annotations needed
}
| ^ use of generic parameter from outer function
error[E0401]: can't use generic parameters from outer function
- --> $DIR/E0401.rs:22:25
+ --> $DIR/E0401.rs:24:25
|
LL | impl<T> Iterator for A<T> {
| ---- `Self` type implicitly declared here, by this `impl`
LL | bfnr::<U, V, W>(x);
| +++++++++++
-error: aborting due to 4 previous errors
+error[E0283]: type annotations needed
+ --> $DIR/E0401.rs:11:5
+ |
+LL | bfnr(x);
+ | ^^^^ cannot infer type of the type parameter `W` declared on the function `bfnr`
+ |
+ = note: multiple `impl`s satisfying `_: Fn<()>` found in the following crates: `alloc`, `core`:
+ - impl<A, F> Fn<A> for &F
+ where A: Tuple, F: Fn<A>, F: ?Sized;
+ - impl<Args, F, A> Fn<Args> for Box<F, A>
+ where Args: Tuple, F: Fn<Args>, A: Allocator, F: ?Sized;
+note: required by a bound in `bfnr`
+ --> $DIR/E0401.rs:4:30
+ |
+LL | fn bfnr<U, V: Baz<U>, W: Fn()>(y: T) {
+ | ^^^^ required by this bound in `bfnr`
+help: consider specifying the type arguments in the function call
+ |
+LL | bfnr::<U, V, W>(x);
+ | +++++++++++
+
+error: aborting due to 5 previous errors
-Some errors have detailed explanations: E0282, E0401.
+Some errors have detailed explanations: E0282, E0283, E0401.
For more information about an error, try `rustc --explain E0282`.
-fn main () {
+fn main() {
'a: loop {
|| {
+ //~^ ERROR mismatched types
loop { break 'a; } //~ ERROR E0767
}
}
error[E0767]: use of unreachable label `'a`
- --> $DIR/E0767.rs:4:26
+ --> $DIR/E0767.rs:5:26
|
LL | 'a: loop {
| -- unreachable label defined here
-LL | || {
+...
LL | loop { break 'a; }
| ^^ unreachable label `'a`
|
= note: labels are unreachable through functions, closures, async blocks and modules
-error: aborting due to previous error
+error[E0308]: mismatched types
+ --> $DIR/E0767.rs:3:9
+ |
+LL | / || {
+LL | |
+LL | | loop { break 'a; }
+LL | | }
+ | |_________^ expected `()`, found closure
+ |
+ = note: expected unit type `()`
+ found closure `[closure@$DIR/E0767.rs:3:9: 3:11]`
+
+error: aborting due to 2 previous errors
-For more information about this error, try `rustc --explain E0767`.
+Some errors have detailed explanations: E0308, E0767.
+For more information about an error, try `rustc --explain E0308`.
-#![feature(isa_attribute)]
-
#[instruction_set()] //~ ERROR
-fn no_isa_defined() {
-}
+fn no_isa_defined() {}
-fn main() {
-}
+fn main() {}
error[E0778]: `#[instruction_set]` requires an argument
- --> $DIR/E0778.rs:3:1
+ --> $DIR/E0778.rs:1:1
|
LL | #[instruction_set()]
| ^^^^^^^^^^^^^^^^^^^^
-#![feature(isa_attribute)]
-
#[instruction_set(arm::magic)] //~ ERROR
-fn main() {
-
-}
+fn main() {}
error[E0779]: invalid instruction set specified
- --> $DIR/E0779.rs:3:1
+ --> $DIR/E0779.rs:1:1
|
LL | #[instruction_set(arm::magic)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
#[lang="sized"]
trait Sized { }
+#[lang="tuple_trait"]
+trait Tuple { }
+
// Functions
extern "rust-intrinsic" fn f1() {} //~ ERROR intrinsics are subject to change
//~^ ERROR intrinsic must be in
error[E0658]: intrinsics are subject to change
- --> $DIR/feature-gate-abi.rs:13:8
+ --> $DIR/feature-gate-abi.rs:16:8
|
LL | extern "rust-intrinsic" fn f1() {}
| ^^^^^^^^^^^^^^^^
= help: add `#![feature(intrinsics)]` to the crate attributes to enable
error[E0658]: platform intrinsics are experimental and possibly buggy
- --> $DIR/feature-gate-abi.rs:15:8
+ --> $DIR/feature-gate-abi.rs:18:8
|
LL | extern "platform-intrinsic" fn f2() {}
| ^^^^^^^^^^^^^^^^^^^^
= help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
error[E0658]: rust-call ABI is subject to change
- --> $DIR/feature-gate-abi.rs:17:8
+ --> $DIR/feature-gate-abi.rs:20:8
|
LL | extern "rust-call" fn f4(_: ()) {}
| ^^^^^^^^^^^
= help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
error[E0658]: efiapi ABI is experimental and subject to change
- --> $DIR/feature-gate-abi.rs:18:8
+ --> $DIR/feature-gate-abi.rs:21:8
|
LL | extern "efiapi" fn f10() {}
| ^^^^^^^^
= help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
error[E0658]: intrinsics are subject to change
- --> $DIR/feature-gate-abi.rs:22:12
+ --> $DIR/feature-gate-abi.rs:25:12
|
LL | extern "rust-intrinsic" fn m1();
| ^^^^^^^^^^^^^^^^
= help: add `#![feature(intrinsics)]` to the crate attributes to enable
error[E0658]: platform intrinsics are experimental and possibly buggy
- --> $DIR/feature-gate-abi.rs:24:12
+ --> $DIR/feature-gate-abi.rs:27:12
|
LL | extern "platform-intrinsic" fn m2();
| ^^^^^^^^^^^^^^^^^^^^
= help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
error[E0658]: rust-call ABI is subject to change
- --> $DIR/feature-gate-abi.rs:26:12
+ --> $DIR/feature-gate-abi.rs:29:12
|
LL | extern "rust-call" fn m4(_: ());
| ^^^^^^^^^^^
= help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
error[E0658]: efiapi ABI is experimental and subject to change
- --> $DIR/feature-gate-abi.rs:27:12
+ --> $DIR/feature-gate-abi.rs:30:12
|
LL | extern "efiapi" fn m10();
| ^^^^^^^^
= help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
error[E0658]: rust-call ABI is subject to change
- --> $DIR/feature-gate-abi.rs:29:12
+ --> $DIR/feature-gate-abi.rs:32:12
|
LL | extern "rust-call" fn dm4(_: ()) {}
| ^^^^^^^^^^^
= help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
error[E0658]: efiapi ABI is experimental and subject to change
- --> $DIR/feature-gate-abi.rs:30:12
+ --> $DIR/feature-gate-abi.rs:33:12
|
LL | extern "efiapi" fn dm10() {}
| ^^^^^^^^
= help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
error[E0658]: intrinsics are subject to change
- --> $DIR/feature-gate-abi.rs:37:12
+ --> $DIR/feature-gate-abi.rs:40:12
|
LL | extern "rust-intrinsic" fn m1() {}
| ^^^^^^^^^^^^^^^^
= help: add `#![feature(intrinsics)]` to the crate attributes to enable
error[E0658]: platform intrinsics are experimental and possibly buggy
- --> $DIR/feature-gate-abi.rs:39:12
+ --> $DIR/feature-gate-abi.rs:42:12
|
LL | extern "platform-intrinsic" fn m2() {}
| ^^^^^^^^^^^^^^^^^^^^
= help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
error[E0658]: rust-call ABI is subject to change
- --> $DIR/feature-gate-abi.rs:41:12
+ --> $DIR/feature-gate-abi.rs:44:12
|
LL | extern "rust-call" fn m4(_: ()) {}
| ^^^^^^^^^^^
= help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
error[E0658]: efiapi ABI is experimental and subject to change
- --> $DIR/feature-gate-abi.rs:42:12
+ --> $DIR/feature-gate-abi.rs:45:12
|
LL | extern "efiapi" fn m10() {}
| ^^^^^^^^
= help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
error[E0658]: intrinsics are subject to change
- --> $DIR/feature-gate-abi.rs:47:12
+ --> $DIR/feature-gate-abi.rs:50:12
|
LL | extern "rust-intrinsic" fn im1() {}
| ^^^^^^^^^^^^^^^^
= help: add `#![feature(intrinsics)]` to the crate attributes to enable
error[E0658]: platform intrinsics are experimental and possibly buggy
- --> $DIR/feature-gate-abi.rs:49:12
+ --> $DIR/feature-gate-abi.rs:52:12
|
LL | extern "platform-intrinsic" fn im2() {}
| ^^^^^^^^^^^^^^^^^^^^
= help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
error[E0658]: rust-call ABI is subject to change
- --> $DIR/feature-gate-abi.rs:51:12
+ --> $DIR/feature-gate-abi.rs:54:12
|
LL | extern "rust-call" fn im4(_: ()) {}
| ^^^^^^^^^^^
= help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
error[E0658]: efiapi ABI is experimental and subject to change
- --> $DIR/feature-gate-abi.rs:52:12
+ --> $DIR/feature-gate-abi.rs:55:12
|
LL | extern "efiapi" fn im10() {}
| ^^^^^^^^
= help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
error[E0658]: intrinsics are subject to change
- --> $DIR/feature-gate-abi.rs:56:18
+ --> $DIR/feature-gate-abi.rs:59:18
|
LL | type A1 = extern "rust-intrinsic" fn();
| ^^^^^^^^^^^^^^^^
= help: add `#![feature(intrinsics)]` to the crate attributes to enable
error[E0658]: platform intrinsics are experimental and possibly buggy
- --> $DIR/feature-gate-abi.rs:57:18
+ --> $DIR/feature-gate-abi.rs:60:18
|
LL | type A2 = extern "platform-intrinsic" fn();
| ^^^^^^^^^^^^^^^^^^^^
= help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
error[E0658]: rust-call ABI is subject to change
- --> $DIR/feature-gate-abi.rs:58:18
+ --> $DIR/feature-gate-abi.rs:61:18
|
LL | type A4 = extern "rust-call" fn(_: ());
| ^^^^^^^^^^^
= help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
error[E0658]: efiapi ABI is experimental and subject to change
- --> $DIR/feature-gate-abi.rs:59:19
+ --> $DIR/feature-gate-abi.rs:62:19
|
LL | type A10 = extern "efiapi" fn();
| ^^^^^^^^
= help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
error[E0658]: intrinsics are subject to change
- --> $DIR/feature-gate-abi.rs:62:8
+ --> $DIR/feature-gate-abi.rs:65:8
|
LL | extern "rust-intrinsic" {}
| ^^^^^^^^^^^^^^^^
= help: add `#![feature(intrinsics)]` to the crate attributes to enable
error[E0658]: platform intrinsics are experimental and possibly buggy
- --> $DIR/feature-gate-abi.rs:63:8
+ --> $DIR/feature-gate-abi.rs:66:8
|
LL | extern "platform-intrinsic" {}
| ^^^^^^^^^^^^^^^^^^^^
= help: add `#![feature(platform_intrinsics)]` to the crate attributes to enable
error[E0658]: rust-call ABI is subject to change
- --> $DIR/feature-gate-abi.rs:64:8
+ --> $DIR/feature-gate-abi.rs:67:8
|
LL | extern "rust-call" {}
| ^^^^^^^^^^^
= help: add `#![feature(unboxed_closures)]` to the crate attributes to enable
error[E0658]: efiapi ABI is experimental and subject to change
- --> $DIR/feature-gate-abi.rs:65:8
+ --> $DIR/feature-gate-abi.rs:68:8
|
LL | extern "efiapi" {}
| ^^^^^^^^
= help: add `#![feature(abi_efiapi)]` to the crate attributes to enable
error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
- --> $DIR/feature-gate-abi.rs:22:32
+ --> $DIR/feature-gate-abi.rs:25:32
|
LL | extern "rust-intrinsic" fn m1();
| ^^
error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
- --> $DIR/feature-gate-abi.rs:24:36
+ --> $DIR/feature-gate-abi.rs:27:36
|
LL | extern "platform-intrinsic" fn m2();
| ^^
error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
- --> $DIR/feature-gate-abi.rs:13:33
+ --> $DIR/feature-gate-abi.rs:16:33
|
LL | extern "rust-intrinsic" fn f1() {}
| ^^
error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
- --> $DIR/feature-gate-abi.rs:15:37
+ --> $DIR/feature-gate-abi.rs:18:37
|
LL | extern "platform-intrinsic" fn f2() {}
| ^^
error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
- --> $DIR/feature-gate-abi.rs:37:37
+ --> $DIR/feature-gate-abi.rs:40:37
|
LL | extern "rust-intrinsic" fn m1() {}
| ^^
error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
- --> $DIR/feature-gate-abi.rs:39:41
+ --> $DIR/feature-gate-abi.rs:42:41
|
LL | extern "platform-intrinsic" fn m2() {}
| ^^
error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
- --> $DIR/feature-gate-abi.rs:47:38
+ --> $DIR/feature-gate-abi.rs:50:38
|
LL | extern "rust-intrinsic" fn im1() {}
| ^^
error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
- --> $DIR/feature-gate-abi.rs:49:42
+ --> $DIR/feature-gate-abi.rs:52:42
|
LL | extern "platform-intrinsic" fn im2() {}
| ^^
use core::alloc::Layout;
-#[alloc_error_handler] //~ ERROR the `#[alloc_error_handler]` attribute is an experimental feature
+#[alloc_error_handler] //~ ERROR use of unstable library feature 'alloc_error_handler'
fn oom(info: Layout) -> ! {
loop {}
}
#[panic_handler]
-fn panic(_: &core::panic::PanicInfo) -> ! { loop {} }
+fn panic(_: &core::panic::PanicInfo) -> ! {
+ loop {}
+}
-error[E0658]: the `#[alloc_error_handler]` attribute is an experimental feature
- --> $DIR/feature-gate-alloc-error-handler.rs:8:1
+error[E0658]: use of unstable library feature 'alloc_error_handler'
+ --> $DIR/feature-gate-alloc-error-handler.rs:8:3
|
LL | #[alloc_error_handler]
- | ^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^
|
= note: see issue #51540 <https://github.com/rust-lang/rust/issues/51540> for more information
= help: add `#![feature(alloc_error_handler)]` to the crate attributes to enable
--- /dev/null
+fn f() -> impl Fn() -> impl Sized { || () }
+//~^ ERROR `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return
+fn g() -> &'static dyn Fn() -> impl Sized { &|| () }
+//~^ ERROR `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return
+
+fn main() {}
--- /dev/null
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return
+ --> $DIR/feature-gate-impl_trait_in_fn_trait_return.rs:1:24
+ |
+LL | fn f() -> impl Fn() -> impl Sized { || () }
+ | ^^^^^^^^^^
+
+error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return
+ --> $DIR/feature-gate-impl_trait_in_fn_trait_return.rs:3:32
+ |
+LL | fn g() -> &'static dyn Fn() -> impl Sized { &|| () }
+ | ^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0562`.
+++ /dev/null
-#[instruction_set]
-//~^ ERROR the `#[instruction_set]` attribute is an experimental feature [E0658]
-//~| ERROR malformed `instruction_set` attribute input
-//~| ERROR must specify an instruction set [E0778]
-fn main() {
-}
+++ /dev/null
-error: malformed `instruction_set` attribute input
- --> $DIR/feature-gate-isa_attribute.rs:1:1
- |
-LL | #[instruction_set]
- | ^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[instruction_set(set)]`
-
-error[E0658]: the `#[instruction_set]` attribute is an experimental feature
- --> $DIR/feature-gate-isa_attribute.rs:1:1
- |
-LL | #[instruction_set]
- | ^^^^^^^^^^^^^^^^^^
- |
- = note: see issue #74727 <https://github.com/rust-lang/rust/issues/74727> for more information
- = help: add `#![feature(isa_attribute)]` to the crate attributes to enable
-
-error[E0778]: must specify an instruction set
- --> $DIR/feature-gate-isa_attribute.rs:1:1
- |
-LL | #[instruction_set]
- | ^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0658, E0778.
-For more information about an error, try `rustc --explain E0658`.
--- /dev/null
+fn main() {
+ // 1 byte in UTF-8
+ format!("\u{000041}{a}"); //~ ERROR cannot find value
+ format!("\u{0041}{a}"); //~ ERROR cannot find value
+ format!("\u{41}{a}"); //~ ERROR cannot find value
+ format!("\u{0}{a}"); //~ ERROR cannot find value
+
+ // 2 bytes
+ format!("\u{0df}{a}"); //~ ERROR cannot find value
+ format!("\u{df}{a}"); //~ ERROR cannot find value
+
+ // 3 bytes
+ format!("\u{00211d}{a}"); //~ ERROR cannot find value
+ format!("\u{211d}{a}"); //~ ERROR cannot find value
+
+ // 4 bytes
+ format!("\u{1f4a3}{a}"); //~ ERROR cannot find value
+ format!("\u{10ffff}{a}"); //~ ERROR cannot find value
+}
--- /dev/null
+error[E0425]: cannot find value `a` in this scope
+ --> $DIR/unicode-escape-spans.rs:3:25
+ |
+LL | format!("\u{000041}{a}");
+ | ^ not found in this scope
+
+error[E0425]: cannot find value `a` in this scope
+ --> $DIR/unicode-escape-spans.rs:4:23
+ |
+LL | format!("\u{0041}{a}");
+ | ^ not found in this scope
+
+error[E0425]: cannot find value `a` in this scope
+ --> $DIR/unicode-escape-spans.rs:5:21
+ |
+LL | format!("\u{41}{a}");
+ | ^ not found in this scope
+
+error[E0425]: cannot find value `a` in this scope
+ --> $DIR/unicode-escape-spans.rs:6:20
+ |
+LL | format!("\u{0}{a}");
+ | ^ not found in this scope
+
+error[E0425]: cannot find value `a` in this scope
+ --> $DIR/unicode-escape-spans.rs:9:22
+ |
+LL | format!("\u{0df}{a}");
+ | ^ not found in this scope
+
+error[E0425]: cannot find value `a` in this scope
+ --> $DIR/unicode-escape-spans.rs:10:21
+ |
+LL | format!("\u{df}{a}");
+ | ^ not found in this scope
+
+error[E0425]: cannot find value `a` in this scope
+ --> $DIR/unicode-escape-spans.rs:13:25
+ |
+LL | format!("\u{00211d}{a}");
+ | ^ not found in this scope
+
+error[E0425]: cannot find value `a` in this scope
+ --> $DIR/unicode-escape-spans.rs:14:23
+ |
+LL | format!("\u{211d}{a}");
+ | ^ not found in this scope
+
+error[E0425]: cannot find value `a` in this scope
+ --> $DIR/unicode-escape-spans.rs:17:24
+ |
+LL | format!("\u{1f4a3}{a}");
+ | ^ not found in this scope
+
+error[E0425]: cannot find value `a` in this scope
+ --> $DIR/unicode-escape-spans.rs:18:25
+ |
+LL | format!("\u{10ffff}{a}");
+ | ^ not found in this scope
+
+error: aborting due to 10 previous errors
+
+For more information about this error, try `rustc --explain E0425`.
|
= note: labels are unreachable through functions, closures, async blocks and modules
-error[E0268]: `break` outside of a loop
+error[E0268]: `break` outside of a loop or labeled block
--> $DIR/break-outside-loop.rs:10:15
|
LL | let pth = break;
- | ^^^^^ cannot `break` outside of a loop
+ | ^^^^^ cannot `break` outside of a loop or labeled block
error[E0268]: `continue` outside of a loop
--> $DIR/break-outside-loop.rs:11:17
LL | if cond() { continue }
| ^^^^^^^^ cannot `continue` inside of a closure
-error[E0268]: `break` outside of a loop
+error[E0268]: `break` outside of a loop or labeled block
--> $DIR/break-outside-loop.rs:24:25
|
LL | let unconstrained = break;
- | ^^^^^ cannot `break` outside of a loop
+ | ^^^^^ cannot `break` outside of a loop or labeled block
error[E0267]: `break` inside of a closure
--> $DIR/break-outside-loop.rs:30:13
#![feature(fn_traits)]
#![feature(unboxed_closures)]
+#![feature(tuple_trait)]
-fn foo<F: Fn<T>, T>(f: Option<F>, t: T) {
+fn foo<F: Fn<T>, T:std::marker::Tuple>(f: Option<F>, t: T) {
let y = (f.unwrap()).call(t);
}
error[E0277]: the size for values of type `str` cannot be known at compilation time
- --> $DIR/unsized-ret.rs:9:27
+ --> $DIR/unsized-ret.rs:10:27
|
LL | foo::<fn() -> str, _>(None, ());
| --------------------- ^^^^ doesn't have a size known at compile-time
= help: within `fn() -> str`, the trait `Sized` is not implemented for `str`
= note: required because it appears within the type `fn() -> str`
note: required by a bound in `foo`
- --> $DIR/unsized-ret.rs:4:11
+ --> $DIR/unsized-ret.rs:5:11
|
-LL | fn foo<F: Fn<T>, T>(f: Option<F>, t: T) {
+LL | fn foo<F: Fn<T>, T:std::marker::Tuple>(f: Option<F>, t: T) {
| ^^^^^ required by this bound in `foo`
error[E0277]: the size for values of type `(dyn std::fmt::Display + 'a)` cannot be known at compilation time
- --> $DIR/unsized-ret.rs:12:66
+ --> $DIR/unsized-ret.rs:13:66
|
LL | foo::<for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a), _>(None, (&(),));
| ------------------------------------------------------------ ^^^^ doesn't have a size known at compile-time
= help: within `for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a)`, the trait `for<'a> Sized` is not implemented for `(dyn std::fmt::Display + 'a)`
= note: required because it appears within the type `for<'a> fn(&'a ()) -> (dyn std::fmt::Display + 'a)`
note: required by a bound in `foo`
- --> $DIR/unsized-ret.rs:4:11
+ --> $DIR/unsized-ret.rs:5:11
|
-LL | fn foo<F: Fn<T>, T>(f: Option<F>, t: T) {
+LL | fn foo<F: Fn<T>, T:std::marker::Tuple>(f: Option<F>, t: T) {
| ^^^^^ required by this bound in `foo`
error: aborting due to 2 previous errors
--- /dev/null
+// check-fail
+// known-bug
+// edition: 2021
+
+// We really should accept this, but we need implied bounds between the regions
+// in a generator interior.
+
+pub trait FutureIterator {
+ type Future<'s, 'cx>: Send
+ where
+ 's: 'cx;
+}
+
+fn call<I: FutureIterator>() -> impl Send {
+ async { // a generator checked for autotrait impl `Send`
+ //~^ lifetime bound not satisfied
+ let x = None::<I::Future<'_, '_>>; // a type referencing GAT
+ async {}.await; // a yield point
+ }
+}
+
+fn call2<'a, 'b, I: FutureIterator>() -> impl Send {
+ async { // a generator checked for autotrait impl `Send`
+ //~^ lifetime bound not satisfied
+ let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
+ //~^ lifetime may not live long enough
+ async {}.await; // a yield point
+ }
+}
+
+fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send {
+ async { // a generator checked for autotrait impl `Send`
+ //~^ lifetime bound not satisfied
+ let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
+ async {}.await; // a yield point
+ }
+}
+
+fn main() {}
--- /dev/null
+error: lifetime bound not satisfied
+ --> $DIR/issue-100013.rs:15:5
+ |
+LL | / async { // a generator checked for autotrait impl `Send`
+LL | |
+LL | | let x = None::<I::Future<'_, '_>>; // a type referencing GAT
+LL | | async {}.await; // a yield point
+LL | | }
+ | |_____^
+ |
+note: the lifetime defined here...
+ --> $DIR/issue-100013.rs:17:38
+ |
+LL | let x = None::<I::Future<'_, '_>>; // a type referencing GAT
+ | ^^
+note: ...must outlive the lifetime defined here
+ --> $DIR/issue-100013.rs:17:34
+ |
+LL | let x = None::<I::Future<'_, '_>>; // a type referencing GAT
+ | ^^
+ = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
+
+error: lifetime bound not satisfied
+ --> $DIR/issue-100013.rs:23:5
+ |
+LL | / async { // a generator checked for autotrait impl `Send`
+LL | |
+LL | | let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
+LL | |
+LL | | async {}.await; // a yield point
+LL | | }
+ | |_____^
+ |
+note: the lifetime defined here...
+ --> $DIR/issue-100013.rs:22:14
+ |
+LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send {
+ | ^^
+note: ...must outlive the lifetime defined here
+ --> $DIR/issue-100013.rs:22:10
+ |
+LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send {
+ | ^^
+ = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
+
+error: lifetime may not live long enough
+ --> $DIR/issue-100013.rs:25:17
+ |
+LL | fn call2<'a, 'b, I: FutureIterator>() -> impl Send {
+ | -- -- lifetime `'b` defined here
+ | |
+ | lifetime `'a` defined here
+...
+LL | let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ requires that `'a` must outlive `'b`
+ |
+ = help: consider adding the following bound: `'a: 'b`
+
+error: lifetime bound not satisfied
+ --> $DIR/issue-100013.rs:32:5
+ |
+LL | / async { // a generator checked for autotrait impl `Send`
+LL | |
+LL | | let x = None::<I::Future<'a, 'b>>; // a type referencing GAT
+LL | | async {}.await; // a yield point
+LL | | }
+ | |_____^
+ |
+note: the lifetime defined here...
+ --> $DIR/issue-100013.rs:31:18
+ |
+LL | fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send {
+ | ^^
+note: ...must outlive the lifetime defined here
+ --> $DIR/issue-100013.rs:31:10
+ |
+LL | fn call3<'a: 'b, 'b, I: FutureIterator>() -> impl Send {
+ | ^^
+ = note: this is a known limitation that will be removed in the future (see issue #100013 <https://github.com/rust-lang/rust/issues/100013> for more information)
+
+error: aborting due to 4 previous errors
+
LL | type FooFuture<'a> = impl Trait1;
| ^^^^^^^^^^^
|
- = note: `FooFuture` must be used in combination with a concrete type within the same module
+ = note: `FooFuture` must be used in combination with a concrete type within the same impl
error: aborting due to previous error
//~| ERROR `T` does not live long enough
//~| ERROR `T` does not live long enough
//~| ERROR `T` may not live long enough
+ //~| ERROR `T` may not live long enough
//
// FIXME: This error is bogus, but it arises because we try to validate
// that `<() as Foo<T>>::Type<'a>` is valid, which requires proving
LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+error[E0310]: the parameter type `T` may not live long enough
+ --> $DIR/issue-91139.rs:14:58
+ |
+LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
+ | ^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ |
+help: consider adding an explicit lifetime bound...
+ |
+LL | fn foo<T: 'static>() {
+ | +++++++++
+
error: `T` does not live long enough
--> $DIR/issue-91139.rs:14:58
|
LL | let _: for<'a> fn(<() as Foo<T>>::Type<'a>, &'a T) = |_, _| ();
| ^^^^^^^^^
-error: aborting due to 9 previous errors
+error: aborting due to 10 previous errors
For more information about this error, try `rustc --explain E0310`.
| ----------- in this macro invocation
...
LL | Vec::new();
- | ^^^ not found in this scope
+ | ^^^ use of undeclared type `Vec`
|
= note: this error originates in the macro `::bar::m` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider importing this struct
fn muh() -> Result<(), impl std::fmt::Debug> {
Err("whoops")?;
- Ok(()) //~ ERROR type annotations needed
+ Ok(())
+ //~^ ERROR type annotations needed
}
fn muh2() -> Result<(), impl std::fmt::Debug> {
- return Err(From::from("foo")); //~ ERROR type annotations needed
+ return Err(From::from("foo"));
+ //~^ ERROR type annotations needed
Ok(())
}
fn muh3() -> Result<(), impl std::fmt::Debug> {
- Err(From::from("foo")) //~ ERROR type annotations needed
+ Err(From::from("foo"))
+ //~^ ERROR type annotations needed
}
fn main() {}
| +++++++++
error[E0282]: type annotations needed
- --> $DIR/cross-return-site-inference.rs:37:12
+ --> $DIR/cross-return-site-inference.rs:38:12
|
LL | return Err(From::from("foo"));
| ^^^ cannot infer type of the type parameter `E` declared on the enum `Result`
| +++++++++
error[E0282]: type annotations needed
- --> $DIR/cross-return-site-inference.rs:42:5
+ --> $DIR/cross-return-site-inference.rs:44:5
|
LL | Err(From::from("foo"))
| ^^^ cannot infer type of the type parameter `E` declared on the enum `Result`
--- /dev/null
+#![feature(impl_trait_in_fn_trait_return)]
+use std::fmt::Debug;
+
+fn a() -> impl Fn(&u8) -> impl Debug {
+ |x| x //~ ERROR hidden type for `impl Debug` captures lifetime that does not appear in bounds
+}
+
+fn main() {}
--- /dev/null
+error[E0700]: hidden type for `impl Debug` captures lifetime that does not appear in bounds
+ --> $DIR/impl-fn-hrtb-bounds-2.rs:5:9
+ |
+LL | |x| x
+ | --- ^
+ | |
+ | hidden type `&u8` captures the anonymous lifetime #1 defined here
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0700`.
--- /dev/null
+#![feature(impl_trait_in_fn_trait_return)]
+use std::fmt::Debug;
+
+fn a() -> impl Fn(&u8) -> (impl Debug + '_) {
+ //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
+ |x| x
+}
+
+fn b() -> impl for<'a> Fn(&'a u8) -> (impl Debug + 'a) {
+ //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
+ |x| x
+}
+
+fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) {
+ //~^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
+ |x| x
+}
+
+fn d() -> impl Fn() -> (impl Debug + '_) {
+ //~^ ERROR missing lifetime specifier
+ || ()
+}
+
+fn main() {}
--- /dev/null
+error[E0106]: missing lifetime specifier
+ --> $DIR/impl-fn-hrtb-bounds.rs:19:38
+ |
+LL | fn d() -> impl Fn() -> (impl Debug + '_) {
+ | ^^ expected named lifetime parameter
+ |
+ = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
+help: consider using the `'static` lifetime
+ |
+LL | fn d() -> impl Fn() -> (impl Debug + 'static) {
+ | ~~~~~~~
+
+error: higher kinded lifetime bounds on nested opaque types are not supported yet
+ --> $DIR/impl-fn-hrtb-bounds.rs:4:41
+ |
+LL | fn a() -> impl Fn(&u8) -> (impl Debug + '_) {
+ | ^^
+ |
+note: lifetime declared here
+ --> $DIR/impl-fn-hrtb-bounds.rs:4:19
+ |
+LL | fn a() -> impl Fn(&u8) -> (impl Debug + '_) {
+ | ^
+
+error: higher kinded lifetime bounds on nested opaque types are not supported yet
+ --> $DIR/impl-fn-hrtb-bounds.rs:9:52
+ |
+LL | fn b() -> impl for<'a> Fn(&'a u8) -> (impl Debug + 'a) {
+ | ^^
+ |
+note: lifetime declared here
+ --> $DIR/impl-fn-hrtb-bounds.rs:9:20
+ |
+LL | fn b() -> impl for<'a> Fn(&'a u8) -> (impl Debug + 'a) {
+ | ^^
+
+error: higher kinded lifetime bounds on nested opaque types are not supported yet
+ --> $DIR/impl-fn-hrtb-bounds.rs:14:52
+ |
+LL | fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) {
+ | ^^
+ |
+note: lifetime declared here
+ --> $DIR/impl-fn-hrtb-bounds.rs:14:20
+ |
+LL | fn c() -> impl for<'a> Fn(&'a u8) -> (impl Debug + '_) {
+ | ^^
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0106`.
--- /dev/null
+#![feature(impl_trait_in_fn_trait_return)]
+use std::fmt::Debug;
+
+fn a() -> impl Fn(&u8) -> impl Debug + '_ {
+ //~^ ERROR ambiguous `+` in a type
+ //~^^ ERROR higher kinded lifetime bounds on nested opaque types are not supported yet
+ |x| x
+}
+
+fn b() -> impl Fn() -> impl Debug + Send {
+ //~^ ERROR ambiguous `+` in a type
+ || ()
+}
+
+fn main() {}
--- /dev/null
+error: ambiguous `+` in a type
+ --> $DIR/impl-fn-parsing-ambiguities.rs:4:27
+ |
+LL | fn a() -> impl Fn(&u8) -> impl Debug + '_ {
+ | ^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(impl Debug + '_)`
+
+error: ambiguous `+` in a type
+ --> $DIR/impl-fn-parsing-ambiguities.rs:10:24
+ |
+LL | fn b() -> impl Fn() -> impl Debug + Send {
+ | ^^^^^^^^^^^^^^^^^ help: use parentheses to disambiguate: `(impl Debug + Send)`
+
+error: higher kinded lifetime bounds on nested opaque types are not supported yet
+ --> $DIR/impl-fn-parsing-ambiguities.rs:4:40
+ |
+LL | fn a() -> impl Fn(&u8) -> impl Debug + '_ {
+ | ^^
+ |
+note: lifetime declared here
+ --> $DIR/impl-fn-parsing-ambiguities.rs:4:19
+ |
+LL | fn a() -> impl Fn(&u8) -> impl Debug + '_ {
+ | ^
+
+error: aborting due to 3 previous errors
+
--- /dev/null
+#![feature(impl_trait_in_fn_trait_return)]
+use std::fmt::Debug;
+
+fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
+ //~^ ERROR cannot resolve opaque type
+
+ |x| x
+ //~^ ERROR concrete type differs from previous defining opaque type use
+}
+
+fn _b<'a>() -> impl Fn(&'a u8) -> (impl Debug + 'a) {
+ a()
+}
+
+fn main() {}
--- /dev/null
+error: concrete type differs from previous defining opaque type use
+ --> $DIR/impl-fn-predefined-lifetimes.rs:7:9
+ |
+LL | |x| x
+ | ^ expected `impl Debug + '_`, got `&u8`
+ |
+note: previous use here
+ --> $DIR/impl-fn-predefined-lifetimes.rs:7:5
+ |
+LL | |x| x
+ | ^^^^^
+
+error[E0720]: cannot resolve opaque type
+ --> $DIR/impl-fn-predefined-lifetimes.rs:4:35
+ |
+LL | fn a<'a>() -> impl Fn(&'a u8) -> (impl Debug + '_) {
+ | ^^^^^^^^^^^^^^^ recursive opaque type
+...
+LL | |x| x
+ | ----- returning here with type `[closure@$DIR/impl-fn-predefined-lifetimes.rs:7:5: 7:8]`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0720`.
--- /dev/null
+// run-pass
+#![feature(impl_trait_in_fn_trait_return)]
+use std::fmt::Debug;
+
+fn f_debug() -> impl Fn() -> impl Debug {
+ || ()
+}
+
+fn ff_debug() -> impl Fn() -> impl Fn() -> impl Debug {
+ || f_debug()
+}
+
+fn multi() -> impl Fn() -> (impl Debug + Send) {
+ || ()
+}
+
+fn main() {
+ // Check that `ff_debug` is `() -> (() -> Debug)` and not `(() -> ()) -> Debug`
+ let debug = ff_debug()()();
+ assert_eq!(format!("{:?}", debug), "()");
+
+ let x = multi()();
+ assert_eq!(format!("{:?}", x), "()");
+ fn assert_send(_: &impl Send) {}
+ assert_send(&x);
+}
--- /dev/null
+// check-pass
+// edition:2021
+
+#![feature(async_fn_in_trait, return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+pub trait Foo {
+ async fn bar<'a: 'a>(&'a mut self);
+}
+
+impl Foo for () {
+ async fn bar<'a: 'a>(&'a mut self) {}
+}
+
+pub trait Foo2 {
+ fn bar<'a: 'a>(&'a mut self) -> impl Sized + 'a;
+}
+
+impl Foo2 for () {
+ fn bar<'a: 'a>(&'a mut self) -> impl Sized + 'a {}
+}
+
+fn main() {}
--- /dev/null
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+struct U;
+
+trait Foo {
+ fn bar(&self) -> impl Sized;
+}
+
+impl Foo for U {
+ fn bar<T>(&self) {}
+ //~^ ERROR method `bar` has 1 type parameter but its trait declaration has 0 type parameters
+}
+
+fn main() {
+ U.bar();
+}
--- /dev/null
+error[E0049]: method `bar` has 1 type parameter but its trait declaration has 0 type parameters
+ --> $DIR/generics-mismatch.rs:11:12
+ |
+LL | fn bar(&self) -> impl Sized;
+ | - expected 0 type parameters
+...
+LL | fn bar<T>(&self) {}
+ | ^ found 1 type parameter
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0049`.
--- /dev/null
+// FIXME(compiler-errors): I'm not exactly sure if this is expected to pass or not.
+// But we fixed an ICE anyways.
+
+#![feature(specialization)]
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+trait Foo {
+ fn bar(&self) -> impl Sized;
+}
+
+default impl<U> Foo for U
+where
+ U: Copy,
+{
+ fn bar(&self) -> U {
+ //~^ ERROR method `bar` has an incompatible type for trait
+ *self
+ }
+}
+
+impl Foo for i32 {}
+
+fn main() {
+ 1i32.bar();
+}
--- /dev/null
+error[E0053]: method `bar` has an incompatible type for trait
+ --> $DIR/specialization-broken.rs:16:22
+ |
+LL | default impl<U> Foo for U
+ | - this type parameter
+...
+LL | fn bar(&self) -> U {
+ | ^
+ | |
+ | expected associated type, found type parameter `U`
+ | help: change the output type to match the trait: `impl Sized`
+ |
+note: type in trait
+ --> $DIR/specialization-broken.rs:9:22
+ |
+LL | fn bar(&self) -> impl Sized;
+ | ^^^^^^^^^^
+ = note: expected fn pointer `fn(&U) -> impl Sized`
+ found fn pointer `fn(&U) -> U`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0053`.
--- /dev/null
+// check-pass
+
+#![feature(specialization)]
+#![feature(return_position_impl_trait_in_trait)]
+#![allow(incomplete_features)]
+
+trait Foo {
+ fn bar(&self) -> impl Sized;
+}
+
+impl<U> Foo for U
+where
+ U: Copy,
+{
+ fn bar(&self) -> U {
+ *self
+ }
+}
+
+impl Foo for i32 {}
+
+fn main() {
+ let _: i32 = 1i32.bar();
+}
--- /dev/null
+// check-pass
+
+trait T {}
+
+fn wrap(x: impl T) -> impl T {
+ //~^ WARN function cannot return without recursing
+ wrap(wrap(x))
+}
+
+fn main() {}
--- /dev/null
+warning: function cannot return without recursing
+ --> $DIR/issue-103599.rs:5:1
+ |
+LL | fn wrap(x: impl T) -> impl T {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing
+LL |
+LL | wrap(wrap(x))
+ | ------- recursive call site
+ |
+ = help: a `loop` may express intention better if this is on purpose
+ = note: `#[warn(unconditional_recursion)]` on by default
+
+warning: 1 warning emitted
+
+#![feature(impl_trait_in_fn_trait_return)]
use std::fmt::Debug;
fn fine(x: impl Into<u32>) -> impl Into<u32> { x }
}
fn allowed_in_ret_type() -> impl Fn() -> impl Into<u32> {
-//~^ `impl Trait` only allowed in function and inherent method return types
- || 5
+ || 5u8
}
fn main() {}
error[E0666]: nested `impl Trait` is not allowed
- --> $DIR/nested_impl_trait.rs:5:56
+ --> $DIR/nested_impl_trait.rs:6:56
|
LL | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
| ----------^^^^^^^^^^-
| outer `impl Trait`
error[E0666]: nested `impl Trait` is not allowed
- --> $DIR/nested_impl_trait.rs:9:42
+ --> $DIR/nested_impl_trait.rs:10:42
|
LL | fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
| ----------^^^^^^^^^^-
| outer `impl Trait`
error[E0666]: nested `impl Trait` is not allowed
- --> $DIR/nested_impl_trait.rs:13:37
+ --> $DIR/nested_impl_trait.rs:14:37
|
LL | fn bad_in_arg_position(_: impl Into<impl Debug>) { }
| ----------^^^^^^^^^^-
| outer `impl Trait`
error[E0666]: nested `impl Trait` is not allowed
- --> $DIR/nested_impl_trait.rs:18:44
+ --> $DIR/nested_impl_trait.rs:19:44
|
LL | fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
| ----------^^^^^^^^^^-
| outer `impl Trait`
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return
- --> $DIR/nested_impl_trait.rs:9:32
+ --> $DIR/nested_impl_trait.rs:10:32
|
LL | fn bad_in_fn_syntax(x: fn() -> impl Into<impl Debug>) {}
| ^^^^^^^^^^^^^^^^^^^^^
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return
- --> $DIR/nested_impl_trait.rs:27:42
- |
-LL | fn allowed_in_ret_type() -> impl Fn() -> impl Into<u32> {
- | ^^^^^^^^^^^^^^
-
error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
- --> $DIR/nested_impl_trait.rs:5:46
+ --> $DIR/nested_impl_trait.rs:6:46
|
LL | fn bad_in_ret_position(x: impl Into<u32>) -> impl Into<impl Debug> { x }
| ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Debug`
= note: required for `impl Into<u32>` to implement `Into<impl Debug>`
error[E0277]: the trait bound `impl Debug: From<impl Into<u32>>` is not satisfied
- --> $DIR/nested_impl_trait.rs:18:34
+ --> $DIR/nested_impl_trait.rs:19:34
|
LL | fn bad(x: impl Into<u32>) -> impl Into<impl Debug> { x }
| ^^^^^^^^^^^^^^^^^^^^^ the trait `From<impl Into<u32>>` is not implemented for `impl Debug`
= help: the trait `Into<U>` is implemented for `T`
= note: required for `impl Into<u32>` to implement `Into<impl Debug>`
-error: aborting due to 8 previous errors
+error: aborting due to 7 previous errors
Some errors have detailed explanations: E0277, E0562, E0666.
For more information about an error, try `rustc --explain E0277`.
//! A simple test for testing many permutations of allowedness of
//! impl Trait
+#![feature(impl_trait_in_fn_trait_return)]
use std::fmt::Debug;
// Allowed
fn in_dyn_Fn_parameter_in_return() -> &'static dyn Fn(impl Debug) { panic!() }
//~^ ERROR `impl Trait` only allowed in function and inherent method return types
-// Disallowed
+// Allowed
fn in_dyn_Fn_return_in_return() -> &'static dyn Fn() -> impl Debug { panic!() }
-//~^ ERROR `impl Trait` only allowed in function and inherent method return types
// Disallowed
fn in_impl_Fn_parameter_in_parameters(_: &impl Fn(impl Debug)) { panic!() }
//~^ ERROR `impl Trait` only allowed in function and inherent method return types
//~| ERROR nested `impl Trait` is not allowed
-// Disallowed
+// Allowed
fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() }
-//~^ ERROR `impl Trait` only allowed in function and inherent method return types
// Disallowed
fn in_Fn_parameter_in_generics<F: Fn(impl Debug)> (_: F) { panic!() }
| outer `impl Trait`
error[E0658]: `impl Trait` in type aliases is unstable
- --> $DIR/where-allowed.rs:119:16
+ --> $DIR/where-allowed.rs:118:16
|
LL | type Out = impl Debug;
| ^^^^^^^^^^
= help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
error[E0658]: `impl Trait` in type aliases is unstable
- --> $DIR/where-allowed.rs:154:23
+ --> $DIR/where-allowed.rs:153:23
|
LL | type InTypeAlias<R> = impl Debug;
| ^^^^^^^^^^
= help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
error[E0658]: `impl Trait` in type aliases is unstable
- --> $DIR/where-allowed.rs:157:39
+ --> $DIR/where-allowed.rs:156:39
|
LL | type InReturnInTypeAlias<R> = fn() -> impl Debug;
| ^^^^^^^^^^
= help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer param
- --> $DIR/where-allowed.rs:15:40
+ --> $DIR/where-allowed.rs:16:40
|
LL | fn in_fn_parameter_in_parameters(_: fn(impl Debug)) { panic!() }
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return
- --> $DIR/where-allowed.rs:19:42
+ --> $DIR/where-allowed.rs:20:42
|
LL | fn in_fn_return_in_parameters(_: fn() -> impl Debug) { panic!() }
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer param
- --> $DIR/where-allowed.rs:23:38
+ --> $DIR/where-allowed.rs:24:38
|
LL | fn in_fn_parameter_in_return() -> fn(impl Debug) { panic!() }
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return
- --> $DIR/where-allowed.rs:27:40
+ --> $DIR/where-allowed.rs:28:40
|
LL | fn in_fn_return_in_return() -> fn() -> impl Debug { panic!() }
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait param
- --> $DIR/where-allowed.rs:31:49
+ --> $DIR/where-allowed.rs:32:49
|
LL | fn in_dyn_Fn_parameter_in_parameters(_: &dyn Fn(impl Debug)) { panic!() }
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return
- --> $DIR/where-allowed.rs:35:51
+ --> $DIR/where-allowed.rs:36:51
|
LL | fn in_dyn_Fn_return_in_parameters(_: &dyn Fn() -> impl Debug) { panic!() }
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait param
- --> $DIR/where-allowed.rs:39:55
+ --> $DIR/where-allowed.rs:40:55
|
LL | fn in_dyn_Fn_parameter_in_return() -> &'static dyn Fn(impl Debug) { panic!() }
| ^^^^^^^^^^
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return
- --> $DIR/where-allowed.rs:43:57
- |
-LL | fn in_dyn_Fn_return_in_return() -> &'static dyn Fn() -> impl Debug { panic!() }
- | ^^^^^^^^^^
-
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait param
--> $DIR/where-allowed.rs:47:51
|
LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() }
| ^^^^^^^^^^
-error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return
- --> $DIR/where-allowed.rs:61:59
- |
-LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() }
- | ^^^^^^^^^^
-
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait param
- --> $DIR/where-allowed.rs:65:38
+ --> $DIR/where-allowed.rs:64:38
|
LL | fn in_Fn_parameter_in_generics<F: Fn(impl Debug)> (_: F) { panic!() }
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return
- --> $DIR/where-allowed.rs:69:40
+ --> $DIR/where-allowed.rs:68:40
|
LL | fn in_Fn_return_in_generics<F: Fn() -> impl Debug> (_: F) { panic!() }
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type
- --> $DIR/where-allowed.rs:82:32
+ --> $DIR/where-allowed.rs:81:32
|
LL | struct InBraceStructField { x: impl Debug }
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in path
- --> $DIR/where-allowed.rs:86:41
+ --> $DIR/where-allowed.rs:85:41
|
LL | struct InAdtInBraceStructField { x: Vec<impl Debug> }
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type
- --> $DIR/where-allowed.rs:90:27
+ --> $DIR/where-allowed.rs:89:27
|
LL | struct InTupleStructField(impl Debug);
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type
- --> $DIR/where-allowed.rs:95:25
+ --> $DIR/where-allowed.rs:94:25
|
LL | InBraceVariant { x: impl Debug },
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type
- --> $DIR/where-allowed.rs:97:20
+ --> $DIR/where-allowed.rs:96:20
|
LL | InTupleVariant(impl Debug),
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in trait method return
- --> $DIR/where-allowed.rs:108:23
+ --> $DIR/where-allowed.rs:107:23
|
LL | fn in_return() -> impl Debug;
| ^^^^^^^^^^
= help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `impl` method return
- --> $DIR/where-allowed.rs:125:34
+ --> $DIR/where-allowed.rs:124:34
|
LL | fn in_trait_impl_return() -> impl Debug { () }
| ^^^^^^^^^^
= help: add `#![feature(return_position_impl_trait_in_trait)]` to the crate attributes to enable
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `extern fn` param
- --> $DIR/where-allowed.rs:138:33
+ --> $DIR/where-allowed.rs:137:33
|
LL | fn in_foreign_parameters(_: impl Debug);
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `extern fn` return
- --> $DIR/where-allowed.rs:141:31
+ --> $DIR/where-allowed.rs:140:31
|
LL | fn in_foreign_return() -> impl Debug;
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `fn` pointer return
- --> $DIR/where-allowed.rs:157:39
+ --> $DIR/where-allowed.rs:156:39
|
LL | type InReturnInTypeAlias<R> = fn() -> impl Debug;
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in trait
- --> $DIR/where-allowed.rs:162:16
+ --> $DIR/where-allowed.rs:161:16
|
LL | impl PartialEq<impl Debug> for () {
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type
- --> $DIR/where-allowed.rs:167:24
+ --> $DIR/where-allowed.rs:166:24
|
LL | impl PartialEq<()> for impl Debug {
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type
- --> $DIR/where-allowed.rs:172:6
+ --> $DIR/where-allowed.rs:171:6
|
LL | impl impl Debug {
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type
- --> $DIR/where-allowed.rs:178:24
+ --> $DIR/where-allowed.rs:177:24
|
LL | impl InInherentImplAdt<impl Debug> {
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type
- --> $DIR/where-allowed.rs:184:11
+ --> $DIR/where-allowed.rs:183:11
|
LL | where impl Debug: Debug
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type
- --> $DIR/where-allowed.rs:191:15
+ --> $DIR/where-allowed.rs:190:15
|
LL | where Vec<impl Debug>: Debug
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in bound
- --> $DIR/where-allowed.rs:198:24
+ --> $DIR/where-allowed.rs:197:24
|
LL | where T: PartialEq<impl Debug>
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait param
- --> $DIR/where-allowed.rs:205:17
+ --> $DIR/where-allowed.rs:204:17
|
LL | where T: Fn(impl Debug)
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in `Fn` trait return
- --> $DIR/where-allowed.rs:212:22
+ --> $DIR/where-allowed.rs:211:22
|
LL | where T: Fn() -> impl Debug
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type
- --> $DIR/where-allowed.rs:218:40
+ --> $DIR/where-allowed.rs:217:40
|
LL | struct InStructGenericParamDefault<T = impl Debug>(T);
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type
- --> $DIR/where-allowed.rs:222:36
+ --> $DIR/where-allowed.rs:221:36
|
LL | enum InEnumGenericParamDefault<T = impl Debug> { Variant(T) }
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type
- --> $DIR/where-allowed.rs:226:38
+ --> $DIR/where-allowed.rs:225:38
|
LL | trait InTraitGenericParamDefault<T = impl Debug> {}
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type
- --> $DIR/where-allowed.rs:230:41
+ --> $DIR/where-allowed.rs:229:41
|
LL | type InTypeAliasGenericParamDefault<T = impl Debug> = T;
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type
- --> $DIR/where-allowed.rs:234:11
+ --> $DIR/where-allowed.rs:233:11
|
LL | impl <T = impl Debug> T {}
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in type
- --> $DIR/where-allowed.rs:241:40
+ --> $DIR/where-allowed.rs:240:40
|
LL | fn in_method_generic_param_default<T = impl Debug>(_: T) {}
| ^^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in variable binding
- --> $DIR/where-allowed.rs:247:29
+ --> $DIR/where-allowed.rs:246:29
|
LL | let _in_local_variable: impl Fn() = || {};
| ^^^^^^^^^
error[E0562]: `impl Trait` only allowed in function and inherent method return types, not in closure return
- --> $DIR/where-allowed.rs:249:46
+ --> $DIR/where-allowed.rs:248:46
|
LL | let _in_return_in_local_variable = || -> impl Fn() { || {} };
| ^^^^^^^^^
error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
- --> $DIR/where-allowed.rs:234:7
+ --> $DIR/where-allowed.rs:233:7
|
LL | impl <T = impl Debug> T {}
| ^^^^^^^^^^^^^^
= note: `#[deny(invalid_type_param_default)]` on by default
error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions
- --> $DIR/where-allowed.rs:241:36
+ --> $DIR/where-allowed.rs:240:36
|
LL | fn in_method_generic_param_default<T = impl Debug>(_: T) {}
| ^^^^^^^^^^^^^^
= note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
error[E0118]: no nominal type found for inherent implementation
- --> $DIR/where-allowed.rs:234:23
+ --> $DIR/where-allowed.rs:233:23
|
LL | impl <T = impl Debug> T {}
| ^ impl requires a nominal type
|
= note: either implement a trait on it or create a newtype to wrap it instead
-error: aborting due to 49 previous errors
+error: aborting due to 47 previous errors
Some errors have detailed explanations: E0118, E0562, E0658, E0666.
For more information about an error, try `rustc --explain E0118`.
let fut = async {
make_unit()?;
- Ok(()) //~ ERROR type annotations needed
+ Ok(())
+ //~^ ERROR type annotations needed
};
}
fn main() {
let x = |a: (), b: ()| {
Err(a)?;
- Ok(b) //~ ERROR type annotations needed
+ Ok(b)
+ //~^ ERROR type annotations needed
};
}
fn foo(parameters: &HashMap<String, String>) -> bool {
parameters
- .get(&"key".into()) //~ ERROR: type annotations needed
+ .get(&"key".into())
+ //~^ ERROR type annotations needed
.and_then(|found: &String| Some(false))
.unwrap_or(false)
}
+// ignore-wasm32 FIXME: ignoring wasm as it suggests slightly different impls
+
// Regression test for #72616, it used to emit incorrect diagnostics, like:
// error[E0283]: type annotations needed for `String`
// --> src/main.rs:8:30
}
{
if String::from("a") == "a".try_into().unwrap() {}
- //~^ ERROR: type annotations needed
+ //~^ ERROR type annotations needed
+ //~| ERROR type annotations needed
}
{
let _: String = match "_".try_into() {
error[E0283]: type annotations needed
- --> $DIR/issue-72616.rs:20:37
+ --> $DIR/issue-72616.rs:22:37
|
LL | if String::from("a") == "a".try_into().unwrap() {}
| -- ^^^^^^^^
LL | if String::from("a") == <&str as TryInto<T>>::try_into("a").unwrap() {}
| +++++++++++++++++++++++++++++++ ~
-error: aborting due to previous error
+error[E0283]: type annotations needed
+ --> $DIR/issue-72616.rs:22:37
+ |
+LL | if String::from("a") == "a".try_into().unwrap() {}
+ | ^^^^^^^^
+ |
+ = note: multiple `impl`s satisfying `_: TryFrom<&str>` found in the following crates: `core`, `std`:
+ - impl<> TryFrom<&str> for std::sys_common::net::LookupHost;
+ - impl<T, U> TryFrom<U> for T
+ where U: Into<T>;
+ = note: required for `&str` to implement `TryInto<_>`
+help: try using a fully qualified path to specify the expected types
+ |
+LL | if String::from("a") == <&str as TryInto<T>>::try_into("a").unwrap() {}
+ | +++++++++++++++++++++++++++++++ ~
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0283`.
fn g() -> Result<Vec<i32>, ()> {
let l = [1, 2, 3, 4];
- l.iter().map(f).collect()? //~ ERROR type annotations needed
+ l.iter().map(f).collect()?
+ //~^ ERROR type annotations needed
}
fn main() {
+++ /dev/null
-fn func(i: i32) {
- i(); //~ERROR expected function, found `i32`
-}
-fn main() {
- let i = 0i32;
- i(); //~ERROR expected function, found `i32`
-}
+++ /dev/null
-error[E0618]: expected function, found `i32`
- --> $DIR/issue-10969.rs:2:5
- |
-LL | fn func(i: i32) {
- | - `i` has type `i32`
-LL | i();
- | ^--
- | |
- | call expression requires function
-
-error[E0618]: expected function, found `i32`
- --> $DIR/issue-10969.rs:6:5
- |
-LL | let i = 0i32;
- | - `i` has type `i32`
-LL | i();
- | ^--
- | |
- | call expression requires function
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0618`.
-#![feature(unboxed_closures)]
+#![feature(unboxed_closures, tuple_trait)]
-fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
+fn to_fn_once<A:std::marker::Tuple,F:FnOnce<A>>(f: F) -> F { f }
fn do_it(x: &isize) { }
fn main() {
+++ /dev/null
-// this code used to cause an ICE
-
-fn main() {
- let t = Err(0);
- match t {
- Some(k) => match k { //~ ERROR mismatched types
- a => println!("{}", a)
- },
- None => () //~ ERROR mismatched types
- }
-}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/issue-12552.rs:6:5
- |
-LL | match t {
- | - this expression has type `Result<_, {integer}>`
-LL | Some(k) => match k {
- | ^^^^^^^ expected enum `Result`, found enum `Option`
- |
- = note: expected enum `Result<_, {integer}>`
- found enum `Option<_>`
-help: try wrapping the pattern in `Ok`
- |
-LL | Ok(Some(k)) => match k {
- | +++ +
-
-error[E0308]: mismatched types
- --> $DIR/issue-12552.rs:9:5
- |
-LL | match t {
- | - this expression has type `Result<_, {integer}>`
-...
-LL | None => ()
- | ^^^^ expected enum `Result`, found enum `Option`
- |
- = note: expected enum `Result<_, {integer}>`
- found enum `Option<_>`
-help: try wrapping the pattern in `Ok`
- |
-LL | Ok(None) => ()
- | +++ +
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
note: trait defined here, with 1 generic parameter: `Args`
--> $SRC_DIR/core/src/ops/function.rs:LL:COL
|
-LL | pub trait Fn<Args>: FnMut<Args> {
+LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
| ^^ ----
help: add missing generic argument
|
LL | continue
| ^^^^^^^^ cannot `continue` outside of a loop
-error[E0268]: `break` outside of a loop
+error[E0268]: `break` outside of a loop or labeled block
--> $DIR/issue-28105.rs:6:5
|
LL | break
- | ^^^^^ cannot `break` outside of a loop
+ | ^^^^^ cannot `break` outside of a loop or labeled block
error: aborting due to 2 previous errors
-error[E0268]: `break` outside of a loop
+error[E0268]: `break` outside of a loop or labeled block
--> $DIR/issue-43162.rs:3:5
|
LL | break true;
- | ^^^^^^^^^^ cannot `break` outside of a loop
+ | ^^^^^^^^^^ cannot `break` outside of a loop or labeled block
-error[E0268]: `break` outside of a loop
+error[E0268]: `break` outside of a loop or labeled block
--> $DIR/issue-43162.rs:7:5
|
LL | break {};
- | ^^^^^^^^ cannot `break` outside of a loop
+ | ^^^^^^^^ cannot `break` outside of a loop or labeled block
error[E0308]: mismatched types
--> $DIR/issue-43162.rs:1:13
+++ /dev/null
-// check-fail
-// known-bug: #47511
-
-// Regression test for #47511: anonymous lifetimes can appear
-// unconstrained in a return type, but only if they appear just once
-// in the input, as the input to a projection.
-
-fn f(_: X) -> X {
- unimplemented!()
-}
-
-fn g<'a>(_: X<'a>) -> X<'a> {
- unimplemented!()
-}
-
-type X<'a> = <&'a () as Trait>::Value;
-
-trait Trait {
- type Value;
-}
-
-impl<'a> Trait for &'a () {
- type Value = ();
-}
-
-fn main() {}
+++ /dev/null
-error[E0581]: return type references an anonymous lifetime, which is not constrained by the fn input types
- --> $DIR/issue-47511.rs:8:15
- |
-LL | fn f(_: X) -> X {
- | ^
- |
- = note: lifetimes appearing in an associated or opaque type are not considered constrained
- = note: consider introducing a named lifetime parameter
-
-error[E0581]: return type references lifetime `'a`, which is not constrained by the fn input types
- --> $DIR/issue-47511.rs:12:23
- |
-LL | fn g<'a>(_: X<'a>) -> X<'a> {
- | ^^^^^
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0581`.
LL | |bool: [u8; break 'L]| 0;
| ^^ undeclared label `'L`
-error[E0268]: `break` outside of a loop
+error[E0268]: `break` outside of a loop or labeled block
--> $DIR/issue-50576.rs:2:17
|
LL | |bool: [u8; break 'L]| 0;
- | ^^^^^^^^ cannot `break` outside of a loop
+ | ^^^^^^^^ cannot `break` outside of a loop or labeled block
-error[E0268]: `break` outside of a loop
+error[E0268]: `break` outside of a loop or labeled block
--> $DIR/issue-50576.rs:5:16
|
LL | Vec::<[u8; break]>::new();
- | ^^^^^ cannot `break` outside of a loop
+ | ^^^^^ cannot `break` outside of a loop or labeled block
error: aborting due to 3 previous errors
-error[E0268]: `break` outside of a loop
+error[E0268]: `break` outside of a loop or labeled block
--> $DIR/issue-50581.rs:2:14
|
LL | |_: [u8; break]| ();
- | ^^^^^ cannot `break` outside of a loop
+ | ^^^^^ cannot `break` outside of a loop or labeled block
error: aborting due to previous error
+++ /dev/null
-// This previously caused an ICE at:
-// librustc/traits/structural_impls.rs:180: impossible case reached
-
-#![no_main]
-
-use std::borrow::Borrow;
-use std::io;
-use std::io::Write;
-
-trait Constraint {}
-
-struct Container<T> {
- t: T,
-}
-
-struct Borrowed;
-struct Owned;
-
-impl<'a, T> Write for &'a Container<T>
-where
- T: Constraint,
- &'a T: Write,
-{
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- Ok(buf.len())
- }
-
- fn flush(&mut self) -> io::Result<()> {
- Ok(())
- }
-}
-
-impl Borrow<Borrowed> for Owned {
- fn borrow(&self) -> &Borrowed {
- &Borrowed
- }
-}
-
-fn func(owned: Owned) {
- let _: () = Borrow::borrow(&owned); //~ ERROR mismatched types
-}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/issue-50687-ice-on-borrow.rs:40:17
- |
-LL | let _: () = Borrow::borrow(&owned);
- | -- ^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found reference
- | |
- | expected due to this
- |
- = note: expected unit type `()`
- found reference `&_`
-help: consider dereferencing the borrow
- |
-LL | let _: () = *Borrow::borrow(&owned);
- | +
-
-error: aborting due to previous error
-
-For more information about this error, try `rustc --explain E0308`.
+++ /dev/null
-// This test is a minimal version of an ICE in the dropck-eyepatch tests
-// found in the fix for #54943.
-
-// check-pass
-
-fn foo<T>(_t: T) {
-}
-
-fn main() {
- struct A<'a, B: 'a>(&'a B);
- let (a1, a2): (String, A<_>) = (String::from("auto"), A(&"this"));
- foo((a1, a2));
-}
+++ /dev/null
-// This test is a minimal version of an ICE in the dropck-eyepatch tests
-// found in the fix for #54943. In particular, this test is in unreachable
-// code as the initial fix for this ICE only worked if the code was reachable.
-
-// check-pass
-
-fn foo<T>(_t: T) {
-}
-
-fn main() {
- return;
-
- struct A<'a, B: 'a>(&'a B);
- let (a1, a2): (String, A<_>) = (String::from("auto"), A(&"this"));
- foo((a1, a2));
-}
+++ /dev/null
-fn foo<T: 'static>() { }
-
-fn boo<'a>() {
- return;
-
- let x = foo::<&'a u32>();
- //~^ ERROR
-}
-
-fn main() {}
+++ /dev/null
-error: lifetime may not live long enough
- --> $DIR/issue-54943.rs:6:13
- |
-LL | fn boo<'a>() {
- | -- lifetime `'a` defined here
-...
-LL | let x = foo::<&'a u32>();
- | ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
-
-error: aborting due to previous error
-
+++ /dev/null
-const ARR_LEN: usize = Tt::const_val::<[i8; 123]>();
-//~^ ERROR E0790
-
-trait Tt {
- const fn const_val<T: Sized>() -> usize {
- //~^ ERROR functions in traits cannot be declared const
- core::mem::size_of::<T>()
- }
-}
-
-fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] {
- //~^ ERROR evaluation of constant value failed
- //~| ERROR evaluation of constant value failed
- z
-}
-
-fn main() {
- let _ = f([1f32; ARR_LEN]);
-}
+++ /dev/null
-error[E0379]: functions in traits cannot be declared const
- --> $DIR/issue-54954.rs:5:5
- |
-LL | const fn const_val<T: Sized>() -> usize {
- | ^^^^^ functions in traits cannot be const
-
-error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
- --> $DIR/issue-54954.rs:1:24
- |
-LL | const ARR_LEN: usize = Tt::const_val::<[i8; 123]>();
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot call associated function of trait
-...
-LL | / const fn const_val<T: Sized>() -> usize {
-LL | |
-LL | | core::mem::size_of::<T>()
-LL | | }
- | |_____- `Tt::const_val` defined here
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/issue-54954.rs:11:15
- |
-LL | fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] {
- | ^^^^^^^ referenced constant has errors
-
-error[E0080]: evaluation of constant value failed
- --> $DIR/issue-54954.rs:11:34
- |
-LL | fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] {
- | ^^^^^^^ referenced constant has errors
-
-error: aborting due to 4 previous errors
-
-Some errors have detailed explanations: E0080, E0379, E0790.
-For more information about an error, try `rustc --explain E0080`.
fn main() {
let n: u32 = 1;
let mut d: u64 = 2;
- d = d % n.into(); //~ ERROR type annotations needed
+ d = d % n.into();
+ //~^ ERROR type annotations needed
}
|
::: $SRC_DIR/core/src/ops/function.rs:LL:COL
|
-LL | pub trait Fn<Args>: FnMut<Args> {
- | ------------------------------- similarly named trait `Fn` defined here
+LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
+ | -------------------------------------- similarly named trait `Fn` defined here
error: aborting due to previous error
// compile-flags: -Z unpretty=thir-tree
pub fn main() {
- break; //~ ERROR: `break` outside of a loop [E0268]
+ break; //~ ERROR: `break` outside of a loop or labeled block [E0268]
}
-error[E0268]: `break` outside of a loop
+error[E0268]: `break` outside of a loop or labeled block
--> $DIR/issue-83048.rs:4:5
|
LL | break;
- | ^^^^^ cannot `break` outside of a loop
+ | ^^^^^ cannot `break` outside of a loop or labeled block
error: aborting due to previous error
// error-pattern: requires `generator` lang_item
-#![feature(no_core, lang_items, unboxed_closures)]
+#![feature(no_core, lang_items, unboxed_closures, tuple_trait)]
#![no_core]
#[lang = "sized"] pub trait Sized { }
+#[lang = "tuple_trait"] pub trait Tuple { }
+
#[lang = "fn_once"]
#[rustc_paren_sugar]
-pub trait FnOnce<Args> {
+pub trait FnOnce<Args: Tuple> {
type Output;
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+error[E0635]: unknown feature `tuple_trait`
+ --> $DIR/lang-item-missing-generator.rs:2:51
+ |
+LL | #![feature(no_core, lang_items, unboxed_closures, tuple_trait)]
+ | ^^^^^^^^^^^
+
error: requires `generator` lang_item
- --> $DIR/lang-item-missing-generator.rs:15:17
+ --> $DIR/lang-item-missing-generator.rs:17:17
|
LL | pub fn abc() -> impl FnOnce(f32) {
| ^^^^^^^^^^^^^^^^
-error: aborting due to previous error
+error: aborting due to 2 previous errors
+For more information about this error, try `rustc --explain E0635`.
--- /dev/null
+pub trait Trait<'a> {
+ type Assoc;
+}
+
+pub type Alias<'a, T> = <T as Trait<'a>>::Assoc;
--- /dev/null
+// aux-build:upstream_alias.rs
+// check-pass
+
+extern crate upstream_alias;
+
+fn foo<'a, T: for<'b> upstream_alias::Trait<'b>>(_: upstream_alias::Alias<'a, T>) -> &'a () {
+ todo!()
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+
+trait Gats<'a> {
+ type Assoc;
+ type Assoc2;
+}
+
+trait Trait: for<'a> Gats<'a> {
+ fn foo<'a>(_: &mut <Self as Gats<'a>>::Assoc) -> <Self as Gats<'a>>::Assoc2;
+}
+
+impl<'a> Gats<'a> for () {
+ type Assoc = &'a u32;
+ type Assoc2 = ();
+}
+
+type GatsAssoc<'a, T> = <T as Gats<'a>>::Assoc;
+type GatsAssoc2<'a, T> = <T as Gats<'a>>::Assoc2;
+
+impl Trait for () {
+ fn foo<'a>(_: &mut GatsAssoc<'a, Self>) -> GatsAssoc2<'a, Self> {}
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+
+fn f(_: X) -> X {
+ unimplemented!()
+}
+
+fn g<'a>(_: X<'a>) -> X<'a> {
+ unimplemented!()
+}
+
+type X<'a> = <&'a () as Trait>::Value;
+
+trait Trait {
+ type Value;
+}
+
+impl<'a> Trait for &'a () {
+ type Value = ();
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+
+fn f(_: X) -> X {
+ unimplemented!()
+}
+
+fn g<'a>(_: X<'a>) -> X<'a> {
+ unimplemented!()
+}
+
+type X<'a> = &'a ();
+
+fn main() {
+ let _: for<'a> fn(X<'a>) -> X<'a> = g;
+ let _: for<'a> fn(X<'a>) -> X<'a> = f;
+}
--- /dev/null
+// ensures that we don't ICE when there are too many args supplied to the alias.
+
+trait Trait<'a> {
+ type Assoc;
+}
+
+type Alias<'a, T> = <T as Trait<'a>>::Assoc;
+
+fn bar<'a, T: Trait<'a>>(_: Alias<'a, 'a, T>) {}
+//~^ error: this type alias takes 1 lifetime argument but 2 lifetime arguments were supplied
+
+fn main() {}
--- /dev/null
+error[E0107]: this type alias takes 1 lifetime argument but 2 lifetime arguments were supplied
+ --> $DIR/mismatched_arg_count.rs:9:29
+ |
+LL | fn bar<'a, T: Trait<'a>>(_: Alias<'a, 'a, T>) {}
+ | ^^^^^ -- help: remove this lifetime argument
+ | |
+ | expected 1 lifetime argument
+ |
+note: type alias defined here, with 1 lifetime parameter: `'a`
+ --> $DIR/mismatched_arg_count.rs:7:6
+ |
+LL | type Alias<'a, T> = <T as Trait<'a>>::Assoc;
+ | ^^^^^ --
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0107`.
// check-pass
-
-
fn main() {
let x = 1 else { return }; //~ WARN irrefutable `let...else` pattern
+
+ // Multiline else blocks should not get printed
+ let x = 1 else { //~ WARN irrefutable `let...else` pattern
+ eprintln!("problem case encountered");
+ return
+ };
}
warning: irrefutable `let...else` pattern
- --> $DIR/let-else-irrefutable.rs:6:5
+ --> $DIR/let-else-irrefutable.rs:4:5
|
LL | let x = 1 else { return };
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^
|
= note: this pattern will always match, so the `else` clause is useless
= help: consider removing the `else` clause
= note: `#[warn(irrefutable_let_patterns)]` on by default
-warning: 1 warning emitted
+warning: irrefutable `let...else` pattern
+ --> $DIR/let-else-irrefutable.rs:7:5
+ |
+LL | let x = 1 else {
+ | ^^^^^^^^^
+ |
+ = note: this pattern will always match, so the `else` clause is useless
+ = help: consider removing the `else` clause
+
+warning: 2 warnings emitted
--> $DIR/lexical-scopes.rs:3:13
|
LL | struct T { i: i32 }
- | ------------------- you might have meant to refer to this struct
+ | - you might have meant to refer to this struct
LL | fn f<T>() {
| - found this type parameter
LL | let t = T { i: 0 };
panic!()
}
+fn l<'a>(_: &'a str, _: &'a str) -> &str { "" }
+//~^ ERROR missing lifetime specifier
+
+// This is ok because both `'a` are for the same parameter.
+fn m<'a>(_: &'a Foo<'a>) -> &str { "" }
+
fn main() {}
LL | fn k<'a, T: WithLifetime<'a>>(_x: T::Output) -> &'a isize {
| ++
-error: aborting due to 6 previous errors
+error[E0106]: missing lifetime specifier
+ --> $DIR/lifetime-elision-return-type-requires-explicit-lifetime.rs:45:37
+ |
+LL | fn l<'a>(_: &'a str, _: &'a str) -> &str { "" }
+ | ------- ------- ^ expected named lifetime parameter
+ |
+ = help: this function's return type contains a borrowed value with an elided lifetime, but the lifetime cannot be derived from the arguments
+help: consider using the `'a` lifetime
+ |
+LL | fn l<'a>(_: &'a str, _: &'a str) -> &'a str { "" }
+ | ++
+
+error: aborting due to 7 previous errors
For more information about this error, try `rustc --explain E0106`.
b: usize, //~ ERROR field `b` is never read
#[deny(dead_code)]
c: usize, //~ ERROR fields `c` and `e` are never read
- d: usize, //~ WARN fields `d`, `f` and `g` are never read
+ d: usize, //~ WARN fields `d`, `f`, and `g` are never read
#[deny(dead_code)]
e: usize,
f: usize,
-warning: fields `d`, `f` and `g` are never read
+warning: fields `d`, `f`, and `g` are never read
--> $DIR/multiple-dead-codes-in-the-same-struct.rs:10:5
|
LL | struct Bar {
//~| HELP: consider changing the field to be of unit type
struct MultipleUnused(i32, f32, String, u8);
-//~^ ERROR: fields `0`, `1`, `2` and `3` are never read
+//~^ ERROR: fields `0`, `1`, `2`, and `3` are never read
//~| NOTE: fields in this struct
//~| HELP: consider changing the fields to be of unit type
LL | struct SingleUnused(i32, (), String);
| ~~
-error: fields `0`, `1`, `2` and `3` are never read
+error: fields `0`, `1`, `2`, and `3` are never read
--> $DIR/tuple-struct-field.rs:13:23
|
LL | struct MultipleUnused(i32, f32, String, u8);
LL | type U = impl Trait;
| ^^^^^^^^^^
|
- = note: `U` must be used in combination with a concrete type within the same module
+ = note: `U` must be used in combination with a concrete type within the same impl
error: aborting due to 6 previous errors; 2 warnings emitted
--- /dev/null
+// check-pass
+// run-rustfix
+
+#[warn(unreachable_pub)]
+mod inner {
+ #[allow(unused)]
+ pub(crate) enum T {
+ //~^ WARN unreachable `pub` item
+ A(u8),
+ X { a: f32, b: () },
+ }
+}
+
+fn main() {}
--- /dev/null
+// check-pass
+// run-rustfix
+
+#[warn(unreachable_pub)]
+mod inner {
+ #[allow(unused)]
+ pub enum T {
+ //~^ WARN unreachable `pub` item
+ A(u8),
+ X { a: f32, b: () },
+ }
+}
+
+fn main() {}
--- /dev/null
+warning: unreachable `pub` item
+ --> $DIR/issue-103317.rs:7:5
+ |
+LL | pub enum T {
+ | ---^^^^^^^
+ | |
+ | help: consider restricting its visibility: `pub(crate)`
+ |
+ = help: or consider exporting it for use by other crates
+note: the lint level is defined here
+ --> $DIR/issue-103317.rs:4:8
+ |
+LL | #[warn(unreachable_pub)]
+ | ^^^^^^^^^^^^^^^
+
+warning: 1 warning emitted
+
LL | type U = impl Trait;
| ^^^^^^^^^^
|
- = note: `U` must be used in combination with a concrete type within the same module
+ = note: `U` must be used in combination with a concrete type within the same impl
error: aborting due to 7 previous errors; 6 warnings emitted
--- /dev/null
+// aux-build:attr-from-macro.rs
+// run-pass
+
+extern crate attr_from_macro;
+
+attr_from_macro::creator! {
+ struct Foo;
+ enum Bar;
+ enum FooBar;
+}
+
+fn main() {
+ // Checking the `repr(u32)` on the enum.
+ assert_eq!(4, std::mem::size_of::<Bar>());
+ // Checking the `repr(u16)` on the enum.
+ assert_eq!(2, std::mem::size_of::<FooBar>());
+
+ // Checking the Debug impl on the types.
+ eprintln!("{:?} {:?} {:?}", Foo, Bar::A, FooBar::A);
+}
--- /dev/null
+#[macro_export]
+macro_rules! creator {
+ (struct $name1:ident; enum $name2:ident; enum $name3:ident;) => {
+ #[derive(Debug)]
+ pub struct $name1;
+
+ #[derive(Debug)]
+ #[repr(u32)]
+ pub enum $name2 { A }
+
+ #[derive(Debug)]
+ #[repr(u16)]
+ pub enum $name3 { A }
+ }
+}
#[macro_export]
-macro_rules! foo { ($i:ident) => {} }
+macro_rules! foo { () => {} }
#[macro_export]
macro_rules! foo { () => {} } //~ ERROR the name `foo` is defined multiple times
+mod inner1 {
+ #[macro_export]
+ macro_rules! bar { () => {} }
+}
+
+mod inner2 {
+ #[macro_export]
+ macro_rules! bar { () => {} } //~ ERROR the name `bar` is defined multiple times
+}
+
fn main() {}
error[E0428]: the name `foo` is defined multiple times
--> $DIR/issue-38715.rs:5:1
|
-LL | macro_rules! foo { ($i:ident) => {} }
+LL | macro_rules! foo { () => {} }
| ---------------- previous definition of the macro `foo` here
...
LL | macro_rules! foo { () => {} }
|
= note: `foo` must be defined only once in the macro namespace of this module
-error: aborting due to previous error
+error[E0428]: the name `bar` is defined multiple times
+ --> $DIR/issue-38715.rs:14:5
+ |
+LL | macro_rules! bar { () => {} }
+ | ---------------- previous definition of the macro `bar` here
+...
+LL | macro_rules! bar { () => {} }
+ | ^^^^^^^^^^^^^^^^ `bar` redefined here
+ |
+ = note: `bar` must be defined only once in the macro namespace of this module
+
+error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0428`.
--- /dev/null
+// check-pass
+#![feature(marker_trait_attr)]
+
+#[marker]
+trait Marker {}
+
+impl Marker for &'static () {}
+impl Marker for &'static () {}
+
+fn main() {}
--- /dev/null
+#![feature(marker_trait_attr)]
+
+#[marker]
+trait Marker {}
+
+impl Marker for &'_ () {} //~ ERROR type annotations needed
+impl Marker for &'_ () {} //~ ERROR type annotations needed
+
+fn main() {}
--- /dev/null
+error[E0283]: type annotations needed: cannot satisfy `&(): Marker`
+ --> $DIR/overlap-marker-trait-with-underscore-lifetime.rs:6:6
+ |
+LL | impl Marker for &'_ () {}
+ | ^^^^^^
+ |
+note: multiple `impl`s satisfying `&(): Marker` found
+ --> $DIR/overlap-marker-trait-with-underscore-lifetime.rs:6:1
+ |
+LL | impl Marker for &'_ () {}
+ | ^^^^^^^^^^^^^^^^^^^^^^
+LL | impl Marker for &'_ () {}
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0283]: type annotations needed: cannot satisfy `&(): Marker`
+ --> $DIR/overlap-marker-trait-with-underscore-lifetime.rs:7:6
+ |
+LL | impl Marker for &'_ () {}
+ | ^^^^^^
+ |
+note: multiple `impl`s satisfying `&(): Marker` found
+ --> $DIR/overlap-marker-trait-with-underscore-lifetime.rs:6:1
+ |
+LL | impl Marker for &'_ () {}
+ | ^^^^^^^^^^^^^^^^^^^^^^
+LL | impl Marker for &'_ () {}
+ | ^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0283`.
use std::fmt::{Debug, Display};
-#[marker] trait Marker {}
+#[marker]
+trait Marker {}
impl<T: Debug> Marker for T {}
impl<T: Display> Marker for T {}
error[E0277]: the trait bound `NotDebugOrDisplay: Marker` is not satisfied
- --> $DIR/overlap-marker-trait.rs:27:17
+ --> $DIR/overlap-marker-trait.rs:28:17
|
LL | is_marker::<NotDebugOrDisplay>();
| ^^^^^^^^^^^^^^^^^ the trait `Marker` is not implemented for `NotDebugOrDisplay`
|
note: required by a bound in `is_marker`
- --> $DIR/overlap-marker-trait.rs:15:17
+ --> $DIR/overlap-marker-trait.rs:16:17
|
LL | fn is_marker<T: Marker>() { }
| ^^^^^^ required by this bound in `is_marker`
use std::fmt::{Debug, Display};
-#[marker] trait MyMarker {}
+#[marker]
+trait MyMarker {}
impl<T: Debug> MyMarker for T {}
impl<T: Display> MyMarker for T {}
--- /dev/null
+// this code used to cause an ICE
+
+fn main() {
+ let t = Err(0);
+ match t {
+ Some(k) => match k { //~ ERROR mismatched types
+ a => println!("{}", a)
+ },
+ None => () //~ ERROR mismatched types
+ }
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-12552.rs:6:5
+ |
+LL | match t {
+ | - this expression has type `Result<_, {integer}>`
+LL | Some(k) => match k {
+ | ^^^^^^^ expected enum `Result`, found enum `Option`
+ |
+ = note: expected enum `Result<_, {integer}>`
+ found enum `Option<_>`
+help: try wrapping the pattern in `Ok`
+ |
+LL | Ok(Some(k)) => match k {
+ | +++ +
+
+error[E0308]: mismatched types
+ --> $DIR/issue-12552.rs:9:5
+ |
+LL | match t {
+ | - this expression has type `Result<_, {integer}>`
+...
+LL | None => ()
+ | ^^^^ expected enum `Result`, found enum `Option`
+ |
+ = note: expected enum `Result<_, {integer}>`
+ found enum `Option<_>`
+help: try wrapping the pattern in `Ok`
+ |
+LL | Ok(None) => ()
+ | +++ +
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
-#![feature(unboxed_closures)]
+#![feature(unboxed_closures,tuple_trait)]
use std::ops::FnMut;
-fn to_fn_mut<A, F: FnMut<A>>(f: F) -> F { f }
+fn to_fn_mut<A:std::marker::Tuple, F:FnMut<A>>(f: F) -> F { f }
fn call_it<F: FnMut(isize, isize) -> isize>(y: isize, mut f: F) -> isize {
//~^ NOTE required by this bound in `call_it`
-#![feature(unboxed_closures)]
+#![feature(unboxed_closures, tuple_trait)]
-fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
+fn to_fn<A:std::marker::Tuple,F:Fn<A>>(f: F) -> F { f }
fn test(_x: Box<usize>) {}
error[E0597]: `a` does not live long enough
--> $DIR/propagate-approximated-shorter-to-static-comparing-against-free.rs:30:26
|
-LL | let cell = Cell::new(&a);
- | ----------^^-
- | | |
- | | borrowed value does not live long enough
- | argument requires that `a` is borrowed for `'static`
+LL | let cell = Cell::new(&a);
+ | ^^ borrowed value does not live long enough
...
-LL | }
- | - `a` dropped here while still borrowed
+LL | / foo(cell, |cell_a, cell_x| {
+LL | | cell_x.set(cell_a.get()); // forces 'a: 'x, implies 'a = 'static -> borrow error
+LL | | })
+ | |______- argument requires that `a` is borrowed for `'static`
+LL | }
+ | - `a` dropped here while still borrowed
error: aborting due to 2 previous errors
T: Trait<'a>,
{
establish_relationships(value, |value| {
- //~^ ERROR the parameter type `T` may not live long enough
-
// This function call requires that
//
// (a) T: Trait<'a>
// The latter does not hold.
require(value);
+ //~^ ERROR the parameter type `T` may not live long enough
});
}
= note: defining type: supply::<'_#1r, T>
error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/propagate-from-trait-match.rs:32:36
+ --> $DIR/propagate-from-trait-match.rs:43:9
|
-LL | establish_relationships(value, |value| {
- | ____________________________________^
-LL | |
-LL | |
-LL | | // This function call requires that
-... |
-LL | | require(value);
-LL | | });
- | |_____^ ...so that the type `T` will meet its required lifetime bounds
+LL | require(value);
+ | ^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
--- /dev/null
+fn foo<T: 'static>() { }
+
+fn boo<'a>() {
+ return;
+
+ let x = foo::<&'a u32>();
+ //~^ ERROR
+}
+
+fn main() {}
--- /dev/null
+error: lifetime may not live long enough
+ --> $DIR/issue-54943.rs:6:13
+ |
+LL | fn boo<'a>() {
+ | -- lifetime `'a` defined here
+...
+LL | let x = foo::<&'a u32>();
+ | ^^^^^^^^^^^^^^ requires that `'a` must outlive `'static`
+
+error: aborting due to previous error
+
= help: consider adding the following bound: `'b: 'a`
error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/issue-98589-closures-relate-named-regions.rs:26:5
+ --> $DIR/issue-98589-closures-relate-named-regions.rs:26:10
|
LL | || { None::<&'a T>; };
- | ^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ | ^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
| ++++
error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/issue-98589-closures-relate-named-regions.rs:32:5
+ --> $DIR/issue-98589-closures-relate-named-regions.rs:32:10
|
LL | || { None::<&'a T>; };
- | ^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ | ^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
fn test<T>() {
|| {
- //~^ ERROR the parameter type `T` may not live long enough
assert_static::<T>();
+ //~^ ERROR the parameter type `T` may not live long enough
};
}
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/issue-98693.rs:15:5
+ --> $DIR/issue-98693.rs:16:9
|
-LL | / || {
-LL | |
-LL | | assert_static::<T>();
-LL | | };
- | |_____^ ...so that the type `T` will meet its required lifetime bounds
+LL | assert_static::<T>();
+ | ^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
error[E0310]: the parameter type `T` may not live long enough
- --> $DIR/projection-implied-bounds.rs:30:18
+ --> $DIR/projection-implied-bounds.rs:30:36
|
LL | twice(value, |value_ref, item| invoke2(value_ref, item));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
= note: defining type: no_region::<'_#1r, T>
error[E0309]: the associated type `<T as Iterator>::Item` may not live long enough
- --> $DIR/projection-no-regions-closure.rs:25:23
+ --> $DIR/projection-no-regions-closure.rs:25:31
|
LL | with_signature(x, |mut y| Box::new(y.next()))
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `<T as Iterator>::Item: 'a`...
= note: ...so that the type `<T as Iterator>::Item` will meet its required lifetime bounds
= note: defining type: wrong_region::<'_#1r, '_#2r, T>
error[E0309]: the associated type `<T as Iterator>::Item` may not live long enough
- --> $DIR/projection-no-regions-closure.rs:42:23
+ --> $DIR/projection-no-regions-closure.rs:42:31
|
LL | with_signature(x, |mut y| Box::new(y.next()))
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `<T as Iterator>::Item: 'a`...
= note: ...so that the type `<T as Iterator>::Item` will meet its required lifetime bounds
= note: defining type: no_relationships_late::<'_#1r, T>
error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/projection-one-region-closure.rs:45:29
+ --> $DIR/projection-one-region-closure.rs:45:39
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ | ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
= note: defining type: no_relationships_early::<'_#1r, '_#2r, T>
error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/projection-one-region-closure.rs:56:29
+ --> $DIR/projection-one-region-closure.rs:56:39
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ | ^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
= note: defining type: no_relationships_late::<'_#1r, '_#2r, T>
error[E0309]: the associated type `<T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(1, 'c)>>::AssocType` may not live long enough
- --> $DIR/projection-two-region-trait-bound-closure.rs:38:29
+ --> $DIR/projection-two-region-trait-bound-closure.rs:38:39
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `<T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(1, 'c)>>::AssocType: 'a`...
= note: ...so that the type `<T as Anything<ReEarlyBound(0, 'b), ReEarlyBound(1, 'c)>>::AssocType` will meet its required lifetime bounds
= note: defining type: no_relationships_early::<'_#1r, '_#2r, '_#3r, T>
error[E0309]: the associated type `<T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType` may not live long enough
- --> $DIR/projection-two-region-trait-bound-closure.rs:48:29
+ --> $DIR/projection-two-region-trait-bound-closure.rs:48:39
|
LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^
|
= help: consider adding an explicit lifetime bound `<T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType: 'a`...
= note: ...so that the type `<T as Anything<ReEarlyBound(1, 'b), ReEarlyBound(2, 'c)>>::AssocType` will meet its required lifetime bounds
= note: defining type: two_regions::<'_#1r, T>
error: lifetime may not live long enough
- --> $DIR/projection-two-region-trait-bound-closure.rs:87:29
+ --> $DIR/projection-two-region-trait-bound-closure.rs:87:5
|
LL | fn two_regions<'a, 'b, T>(cell: Cell<&'a ()>, t: T)
| -- -- lifetime `'b` defined here
| lifetime `'a` defined here
...
LL | with_signature(cell, t, |cell, t| require(cell, t));
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^ closure body requires that `'b` must outlive `'a`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'b` must outlive `'a`
|
= help: consider adding the following bound: `'b: 'a`
+ = note: requirement occurs because of the type `Cell<&'_#8r ()>`, which makes the generic argument `&'_#8r ()` invariant
+ = note: the struct `Cell<T>` is invariant over the parameter `T`
+ = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
note: external requirements
--> $DIR/projection-two-region-trait-bound-closure.rs:97:29
= note: defining type: generic_fail::<T>
error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/ty-param-closure-approximate-lower-bound.rs:29:24
+ --> $DIR/ty-param-closure-approximate-lower-bound.rs:29:31
|
LL | twice(cell, value, |a, b| invoke(a, b));
- | ^^^^^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ | ^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
= note: defining type: no_region::<'_#1r, T>
error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/ty-param-closure-outlives-from-return-type.rs:26:23
+ --> $DIR/ty-param-closure-outlives-from-return-type.rs:26:27
|
LL | with_signature(x, |y| y)
- | ^^^^^ ...so that the type `T` will meet its required lifetime bounds
+ | ^ ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
#[rustc_regions]
fn no_region<'a, T>(a: Cell<&'a ()>, b: T) {
with_signature(a, b, |x, y| {
- //~^ ERROR the parameter type `T` may not live long enough
- //
// See `correct_region`, which explains the point of this
// test. The only difference is that, in the case of this
// function, there is no where clause *anywhere*, and hence we
// get an error (but reported by the closure creator).
require(&x, &y)
+ //~^ ERROR the parameter type `T` may not live long enough
})
}
T: 'b,
{
with_signature(a, b, |x, y| {
- //~^ ERROR the parameter type `T` may not live long enough
// See `correct_region`
require(&x, &y)
+ //~^ ERROR the parameter type `T` may not live long enough
})
}
= note: defining type: no_region::<T>
error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/ty-param-closure-outlives-from-where-clause.rs:27:26
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:32:9
|
-LL | with_signature(a, b, |x, y| {
- | __________________________^
-LL | |
-LL | | //
-LL | | // See `correct_region`, which explains the point of this
-... |
-LL | | require(&x, &y)
-LL | | })
- | |_____^ ...so that the type `T` will meet its required lifetime bounds
+LL | require(&x, &y)
+ | ^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
| ++++
note: external requirements
- --> $DIR/ty-param-closure-outlives-from-where-clause.rs:43:26
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:42:26
|
LL | with_signature(a, b, |x, y| {
| ^^^^^^
= note: where T: '_#2r
note: no external requirements
- --> $DIR/ty-param-closure-outlives-from-where-clause.rs:39:1
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:38:1
|
LL | / fn correct_region<'a, T>(a: Cell<&'a ()>, b: T)
LL | | where
= note: defining type: correct_region::<'_#1r, T>
note: external requirements
- --> $DIR/ty-param-closure-outlives-from-where-clause.rs:64:26
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:63:26
|
LL | with_signature(a, b, |x, y| {
| ^^^^^^
= note: where T: '_#2r
note: no external requirements
- --> $DIR/ty-param-closure-outlives-from-where-clause.rs:60:1
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:59:1
|
LL | / fn wrong_region<'a, 'b, T>(a: Cell<&'a ()>, b: T)
LL | | where
= note: defining type: wrong_region::<'_#1r, T>
error[E0309]: the parameter type `T` may not live long enough
- --> $DIR/ty-param-closure-outlives-from-where-clause.rs:64:26
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:65:9
|
-LL | with_signature(a, b, |x, y| {
- | __________________________^
-LL | |
-LL | | // See `correct_region`
-LL | | require(&x, &y)
-LL | | })
- | |_____^ ...so that the type `T` will meet its required lifetime bounds
+LL | require(&x, &y)
+ | ^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds
|
help: consider adding an explicit lifetime bound...
|
| ++++
note: external requirements
- --> $DIR/ty-param-closure-outlives-from-where-clause.rs:77:26
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:76:26
|
LL | with_signature(a, b, |x, y| {
| ^^^^^^
= note: where T: '_#3r
note: no external requirements
- --> $DIR/ty-param-closure-outlives-from-where-clause.rs:72:1
+ --> $DIR/ty-param-closure-outlives-from-where-clause.rs:71:1
|
LL | / fn outlives_region<'a, 'b, T>(a: Cell<&'a ()>, b: T)
LL | | where
error[E0597]: `c` does not live long enough
--> $DIR/adt-nullary-enums.rs:33:41
|
-LL | SomeEnum::SomeVariant(Cell::new(&c)),
- | ----------^^-
- | | |
- | | borrowed value does not live long enough
- | argument requires that `c` is borrowed for `'static`
-...
-LL | }
- | - `c` dropped here while still borrowed
+LL | / combine(
+LL | | SomeEnum::SomeVariant(Cell::new(&c)),
+ | | ^^ borrowed value does not live long enough
+LL | | SomeEnum::SomeOtherVariant::<Cell<&'static u32>>,
+LL | | );
+ | |_____- argument requires that `c` is borrowed for `'static`
+LL | }
+ | - `c` dropped here while still borrowed
error[E0597]: `c` does not live long enough
--> $DIR/adt-nullary-enums.rs:41:41
}
impl FnMut<isize> for S {
+ //~^ ERROR type parameter to bare `FnMut` trait must be a tuple
extern "rust-call" fn call_mut(&mut self, z: isize) -> isize {
+ //~^ ERROR functions with the "rust-call" ABI must take a single non-self tuple argument
self.x + self.y + z
}
- //~^^^ ERROR functions with the "rust-call" ABI must take a single non-self argument
}
impl FnOnce<isize> for S {
+ //~^ ERROR type parameter to bare `FnOnce` trait must be a tuple
type Output = isize;
- extern "rust-call" fn call_once(mut self, z: isize) -> isize { self.call_mut(z) }
- //~^ ERROR functions with the "rust-call" ABI must take a single non-self argument
+ extern "rust-call" fn call_once(mut self, z: isize) -> isize {
+ //~^ ERROR functions with the "rust-call" ABI must take a single non-self tuple argument
+ self.call_mut(z)
+ }
}
fn main() {
- let mut s = S {
- x: 1,
- y: 2,
- };
- drop(s(3)) //~ ERROR cannot use call notation
+ let mut s = S { x: 1, y: 2 };
+ drop(s(3))
}
-error: functions with the "rust-call" ABI must take a single non-self argument that is a tuple
- --> $DIR/overloaded-calls-nontuple.rs:11:5
+error[E0059]: type parameter to bare `FnMut` trait must be a tuple
+ --> $DIR/overloaded-calls-nontuple.rs:10:6
|
-LL | extern "rust-call" fn call_mut(&mut self, z: isize) -> isize {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | impl FnMut<isize> for S {
+ | ^^^^^^^^^^^^ the trait `Tuple` is not implemented for `isize`
+ |
+note: required by a bound in `FnMut`
+ --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+ |
+LL | pub trait FnMut<Args: Tuple>: FnOnce<Args> {
+ | ^^^^^ required by this bound in `FnMut`
+
+error[E0059]: type parameter to bare `FnOnce` trait must be a tuple
+ --> $DIR/overloaded-calls-nontuple.rs:18:6
+ |
+LL | impl FnOnce<isize> for S {
+ | ^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `isize`
+ |
+note: required by a bound in `FnOnce`
+ --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+ |
+LL | pub trait FnOnce<Args: Tuple> {
+ | ^^^^^ required by this bound in `FnOnce`
-error: functions with the "rust-call" ABI must take a single non-self argument that is a tuple
- --> $DIR/overloaded-calls-nontuple.rs:19:5
+error[E0277]: functions with the "rust-call" ABI must take a single non-self tuple argument
+ --> $DIR/overloaded-calls-nontuple.rs:12:5
|
-LL | extern "rust-call" fn call_once(mut self, z: isize) -> isize { self.call_mut(z) }
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | extern "rust-call" fn call_mut(&mut self, z: isize) -> isize {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `isize`
-error[E0059]: cannot use call notation; the first type parameter for the function trait is neither a tuple nor unit
- --> $DIR/overloaded-calls-nontuple.rs:28:10
+error[E0277]: functions with the "rust-call" ABI must take a single non-self tuple argument
+ --> $DIR/overloaded-calls-nontuple.rs:21:5
|
-LL | drop(s(3))
- | ^^^^
+LL | extern "rust-call" fn call_once(mut self, z: isize) -> isize {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Tuple` is not implemented for `isize`
-error: aborting due to 3 previous errors
+error: aborting due to 4 previous errors
-For more information about this error, try `rustc --explain E0059`.
+Some errors have detailed explanations: E0059, E0277.
+For more information about an error, try `rustc --explain E0059`.
--- /dev/null
+#![allow(dead_code)]
+
+#[derive(Default)]
+struct V3 {
+ x: f32,
+ y: f32,
+ z: f32,
+}
+
+fn pz(v: V3) {
+ let _ = V3 { z: 0.0, ...v};
+ //~^ ERROR expected `..`
+
+ let _ = V3 { z: 0.0, ...Default::default() };
+ //~^ ERROR expected `..`
+
+ let _ = V3 { z: 0.0, ... };
+ //~^ expected identifier
+ //~| ERROR missing fields `x` and `y` in initializer of `V3`
+
+ let V3 { z: val, ... } = v;
+ //~^ ERROR expected field pattern
+}
+
+fn main() {}
--- /dev/null
+error: expected `..`, found `...`
+ --> $DIR/issue-102806.rs:11:26
+ |
+LL | let _ = V3 { z: 0.0, ...v};
+ | ^^^
+ |
+help: use `..` to fill in the rest of the fields
+ |
+LL | let _ = V3 { z: 0.0, ..v};
+ | ~~
+
+error: expected `..`, found `...`
+ --> $DIR/issue-102806.rs:14:26
+ |
+LL | let _ = V3 { z: 0.0, ...Default::default() };
+ | ^^^
+ |
+help: use `..` to fill in the rest of the fields
+ |
+LL | let _ = V3 { z: 0.0, ..Default::default() };
+ | ~~
+
+error: expected identifier, found `...`
+ --> $DIR/issue-102806.rs:17:26
+ |
+LL | let _ = V3 { z: 0.0, ... };
+ | -- ^^^ expected identifier
+ | |
+ | while parsing this struct
+
+error: expected field pattern, found `...`
+ --> $DIR/issue-102806.rs:21:22
+ |
+LL | let V3 { z: val, ... } = v;
+ | ^^^ help: to omit remaining fields, use one fewer `.`: `..`
+
+error[E0063]: missing fields `x` and `y` in initializer of `V3`
+ --> $DIR/issue-102806.rs:17:13
+ |
+LL | let _ = V3 { z: 0.0, ... };
+ | ^^ missing `x` and `y`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0063`.
--- /dev/null
+// error-pattern: this file contains an unclosed delimiter
+// error-pattern: expected value, found struct `R`
+struct R { }
+struct S {
+ x: [u8; R
--- /dev/null
+error: this file contains an unclosed delimiter
+ --> $DIR/issue-103451.rs:5:15
+ |
+LL | struct S {
+ | - unclosed delimiter
+LL | x: [u8; R
+ | - ^
+ | |
+ | unclosed delimiter
+
+error: this file contains an unclosed delimiter
+ --> $DIR/issue-103451.rs:5:15
+ |
+LL | struct S {
+ | - unclosed delimiter
+LL | x: [u8; R
+ | - ^
+ | |
+ | unclosed delimiter
+
+error[E0423]: expected value, found struct `R`
+ --> $DIR/issue-103451.rs:5:13
+ |
+LL | struct R { }
+ | ------------ `R` defined here
+LL | struct S {
+LL | x: [u8; R
+ | ^ help: use struct literal syntax instead: `R {}`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0423`.
|
::: $SRC_DIR/core/src/ops/function.rs:LL:COL
|
-LL | pub trait Fn<Args>: FnMut<Args> {
- | ------------------------------- similarly named trait `Fn` defined here
+LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
+ | -------------------------------------- similarly named trait `Fn` defined here
error[E0405]: cannot find trait `r#fn` in this scope
--> $DIR/kw-in-trait-bounds.rs:17:4
|
::: $SRC_DIR/core/src/ops/function.rs:LL:COL
|
-LL | pub trait Fn<Args>: FnMut<Args> {
- | ------------------------------- similarly named trait `Fn` defined here
+LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
+ | -------------------------------------- similarly named trait `Fn` defined here
error[E0405]: cannot find trait `r#fn` in this scope
--> $DIR/kw-in-trait-bounds.rs:3:27
|
::: $SRC_DIR/core/src/ops/function.rs:LL:COL
|
-LL | pub trait Fn<Args>: FnMut<Args> {
- | ------------------------------- similarly named trait `Fn` defined here
+LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
+ | -------------------------------------- similarly named trait `Fn` defined here
error[E0405]: cannot find trait `r#fn` in this scope
--> $DIR/kw-in-trait-bounds.rs:3:41
|
::: $SRC_DIR/core/src/ops/function.rs:LL:COL
|
-LL | pub trait Fn<Args>: FnMut<Args> {
- | ------------------------------- similarly named trait `Fn` defined here
+LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
+ | -------------------------------------- similarly named trait `Fn` defined here
error[E0405]: cannot find trait `r#struct` in this scope
--> $DIR/kw-in-trait-bounds.rs:24:10
--- /dev/null
+fn a() {
+ if let () = () 'a {}
+ //~^ ERROR labeled expression must be followed by `:`
+ //~| ERROR expected `{`, found `'a`
+}
+
+fn b() {
+ if true 'a {}
+ //~^ ERROR labeled expression must be followed by `:`
+ //~| ERROR expected `{`, found `'a`
+}
+
+fn c() {
+ loop 'a {}
+ //~^ ERROR labeled expression must be followed by `:`
+ //~| ERROR expected `{`, found `'a`
+}
+
+fn d() {
+ while true 'a {}
+ //~^ ERROR labeled expression must be followed by `:`
+ //~| ERROR expected `{`, found `'a`
+}
+
+fn e() {
+ while let () = () 'a {}
+ //~^ ERROR labeled expression must be followed by `:`
+ //~| ERROR expected `{`, found `'a`
+}
+
+fn f() {
+ for _ in 0..0 'a {}
+ //~^ ERROR labeled expression must be followed by `:`
+ //~| ERROR expected `{`, found `'a`
+}
+
+fn g() {
+ unsafe 'a {}
+ //~^ ERROR labeled expression must be followed by `:`
+ //~| ERROR expected `{`, found `'a`
+}
+
+fn main() {}
--- /dev/null
+error: labeled expression must be followed by `:`
+ --> $DIR/label-after-block-like.rs:2:20
+ |
+LL | if let () = () 'a {}
+ | ---^^
+ | | |
+ | | help: add `:` after the label
+ | the label
+ |
+ = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+
+error: expected `{`, found `'a`
+ --> $DIR/label-after-block-like.rs:2:20
+ |
+LL | if let () = () 'a {}
+ | ^^ expected `{`
+ |
+note: the `if` expression is missing a block after this condition
+ --> $DIR/label-after-block-like.rs:2:8
+ |
+LL | if let () = () 'a {}
+ | ^^^^^^^^^^^
+help: try placing this code inside a block
+ |
+LL | if let () = () { 'a {} }
+ | + +
+
+error: labeled expression must be followed by `:`
+ --> $DIR/label-after-block-like.rs:8:13
+ |
+LL | if true 'a {}
+ | ---^^
+ | | |
+ | | help: add `:` after the label
+ | the label
+ |
+ = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+
+error: expected `{`, found `'a`
+ --> $DIR/label-after-block-like.rs:8:13
+ |
+LL | if true 'a {}
+ | ^^ expected `{`
+ |
+note: the `if` expression is missing a block after this condition
+ --> $DIR/label-after-block-like.rs:8:8
+ |
+LL | if true 'a {}
+ | ^^^^
+help: try placing this code inside a block
+ |
+LL | if true { 'a {} }
+ | + +
+
+error: labeled expression must be followed by `:`
+ --> $DIR/label-after-block-like.rs:14:10
+ |
+LL | loop 'a {}
+ | ---^^
+ | | |
+ | | help: add `:` after the label
+ | the label
+ |
+ = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+
+error: expected `{`, found `'a`
+ --> $DIR/label-after-block-like.rs:14:10
+ |
+LL | loop 'a {}
+ | ---- ^^ expected `{`
+ | |
+ | while parsing this `loop` expression
+ |
+help: try placing this code inside a block
+ |
+LL | loop { 'a {} }
+ | + +
+
+error: labeled expression must be followed by `:`
+ --> $DIR/label-after-block-like.rs:20:16
+ |
+LL | while true 'a {}
+ | ---^^
+ | | |
+ | | help: add `:` after the label
+ | the label
+ |
+ = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+
+error: expected `{`, found `'a`
+ --> $DIR/label-after-block-like.rs:20:16
+ |
+LL | while true 'a {}
+ | ----- ---- ^^ expected `{`
+ | | |
+ | | this `while` condition successfully parsed
+ | while parsing the body of this `while` expression
+ |
+help: try placing this code inside a block
+ |
+LL | while true { 'a {} }
+ | + +
+
+error: labeled expression must be followed by `:`
+ --> $DIR/label-after-block-like.rs:26:23
+ |
+LL | while let () = () 'a {}
+ | ---^^
+ | | |
+ | | help: add `:` after the label
+ | the label
+ |
+ = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+
+error: expected `{`, found `'a`
+ --> $DIR/label-after-block-like.rs:26:23
+ |
+LL | while let () = () 'a {}
+ | ----- ----------- ^^ expected `{`
+ | | |
+ | | this `while` condition successfully parsed
+ | while parsing the body of this `while` expression
+ |
+help: try placing this code inside a block
+ |
+LL | while let () = () { 'a {} }
+ | + +
+
+error: labeled expression must be followed by `:`
+ --> $DIR/label-after-block-like.rs:32:19
+ |
+LL | for _ in 0..0 'a {}
+ | ---^^
+ | | |
+ | | help: add `:` after the label
+ | the label
+ |
+ = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+
+error: expected `{`, found `'a`
+ --> $DIR/label-after-block-like.rs:32:19
+ |
+LL | for _ in 0..0 'a {}
+ | ^^ expected `{`
+ |
+help: try placing this code inside a block
+ |
+LL | for _ in 0..0 { 'a {} }
+ | + +
+
+error: labeled expression must be followed by `:`
+ --> $DIR/label-after-block-like.rs:38:12
+ |
+LL | unsafe 'a {}
+ | ---^^
+ | | |
+ | | help: add `:` after the label
+ | the label
+ |
+ = note: labels are used before loops and blocks, allowing e.g., `break 'label` to them
+
+error: expected `{`, found `'a`
+ --> $DIR/label-after-block-like.rs:38:12
+ |
+LL | unsafe 'a {}
+ | ------ ^^ expected `{`
+ | |
+ | while parsing this `unsafe` expression
+ |
+help: try placing this code inside a block
+ |
+LL | unsafe { 'a {} }
+ | + +
+
+error: aborting due to 14 previous errors
+
-// check-pass
+macro_rules! sink {
+ ($tt:tt) => {()}
+}
fn main() {
let _ = "Foo"_;
- //~^ WARNING underscore literal suffix is not allowed
- //~| WARNING this was previously accepted
- //~| NOTE issue #42326
+ //~^ ERROR underscore literal suffix is not allowed
+
+ // This is ok, because `__` is a valid identifier and the macro consumes it
+ // before proper parsing happens.
+ let _ = sink!("Foo"__);
+
+ // This is not ok, even as an input to a macro, because the `_` suffix is
+ // never allowed.
+ sink!("Foo"_);
+ //~^ ERROR underscore literal suffix is not allowed
}
-warning: underscore literal suffix is not allowed
- --> $DIR/underscore-suffix-for-string.rs:4:18
+error: underscore literal suffix is not allowed
+ --> $DIR/underscore-suffix-for-string.rs:6:18
|
LL | let _ = "Foo"_;
| ^
+
+error: underscore literal suffix is not allowed
+ --> $DIR/underscore-suffix-for-string.rs:15:16
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: see issue #42326 <https://github.com/rust-lang/rust/issues/42326> for more information
+LL | sink!("Foo"_);
+ | ^
-warning: 1 warning emitted
+error: aborting due to 2 previous errors
+++ /dev/null
-#![feature(rustc_attrs)]
-
-#[rustc_effective_visibility]
-mod outer { //~ ERROR Public: pub(crate), Exported: pub(crate), Reachable: pub(crate), ReachableFromImplTrait: pub(crate)
- #[rustc_effective_visibility]
- pub mod inner1 { //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-
- #[rustc_effective_visibility]
- extern "C" {} //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-
- #[rustc_effective_visibility]
- pub trait PubTrait { //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
- #[rustc_effective_visibility]
- const A: i32; //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
- #[rustc_effective_visibility]
- type B; //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
- }
-
- #[rustc_effective_visibility]
- struct PrivStruct; //~ ERROR not in the table
-
- #[rustc_effective_visibility]
- pub union PubUnion { //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
- #[rustc_effective_visibility]
- a: u8, //~ ERROR not in the table
- #[rustc_effective_visibility]
- pub b: u8, //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
- }
-
- #[rustc_effective_visibility]
- pub enum Enum { //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
- #[rustc_effective_visibility]
- A( //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
- #[rustc_effective_visibility]
- PubUnion, //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
- ),
- }
- }
-
- #[rustc_effective_visibility]
- macro_rules! none_macro { //~ ERROR Public: pub(crate), Exported: pub(crate), Reachable: pub(crate), ReachableFromImplTrait: pub(crate)
- () => {};
- }
-
- #[macro_export]
- #[rustc_effective_visibility]
- macro_rules! public_macro { //~ ERROR Public: pub, Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
- () => {};
- }
-
- #[rustc_effective_visibility]
- pub struct ReachableStruct { //~ ERROR Public: pub(crate), Exported: pub(crate), Reachable: pub, ReachableFromImplTrait: pub
- #[rustc_effective_visibility]
- pub a: u8, //~ ERROR Public: pub(crate), Exported: pub(crate), Reachable: pub, ReachableFromImplTrait: pub
- }
-}
-
-#[rustc_effective_visibility]
-pub use outer::inner1; //~ ERROR Public: pub, Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-
-pub fn foo() -> outer::ReachableStruct { outer::ReachableStruct {a: 0} }
-
-mod half_public_import {
- #[rustc_effective_visibility]
- pub type HalfPublicImport = u8; //~ ERROR Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
- #[rustc_effective_visibility]
- #[allow(non_upper_case_globals)]
- pub(crate) const HalfPublicImport: u8 = 0; //~ ERROR Public: pub(crate), Exported: pub(crate), Reachable: pub(crate), ReachableFromImplTrait: pub(crate)
-}
-
-#[rustc_effective_visibility]
-pub use half_public_import::HalfPublicImport; //~ ERROR Public: pub, Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
- //~^ ERROR Public: pub, Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
-
-fn main() {}
+++ /dev/null
-error: Public: pub(crate), Exported: pub(crate), Reachable: pub(crate), ReachableFromImplTrait: pub(crate)
- --> $DIR/access_levels.rs:4:1
- |
-LL | mod outer {
- | ^^^^^^^^^
-
-error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
- --> $DIR/access_levels.rs:6:5
- |
-LL | pub mod inner1 {
- | ^^^^^^^^^^^^^^
-
-error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
- --> $DIR/access_levels.rs:9:9
- |
-LL | extern "C" {}
- | ^^^^^^^^^^^^^
-
-error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
- --> $DIR/access_levels.rs:12:9
- |
-LL | pub trait PubTrait {
- | ^^^^^^^^^^^^^^^^^^
-
-error: not in the table
- --> $DIR/access_levels.rs:20:9
- |
-LL | struct PrivStruct;
- | ^^^^^^^^^^^^^^^^^
-
-error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
- --> $DIR/access_levels.rs:23:9
- |
-LL | pub union PubUnion {
- | ^^^^^^^^^^^^^^^^^^
-
-error: not in the table
- --> $DIR/access_levels.rs:25:13
- |
-LL | a: u8,
- | ^^^^^
-
-error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
- --> $DIR/access_levels.rs:27:13
- |
-LL | pub b: u8,
- | ^^^^^^^^^
-
-error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
- --> $DIR/access_levels.rs:31:9
- |
-LL | pub enum Enum {
- | ^^^^^^^^^^^^^
-
-error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
- --> $DIR/access_levels.rs:33:13
- |
-LL | A(
- | ^
-
-error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
- --> $DIR/access_levels.rs:35:17
- |
-LL | PubUnion,
- | ^^^^^^^^
-
-error: Public: pub(crate), Exported: pub(crate), Reachable: pub(crate), ReachableFromImplTrait: pub(crate)
- --> $DIR/access_levels.rs:41:5
- |
-LL | macro_rules! none_macro {
- | ^^^^^^^^^^^^^^^^^^^^^^^
-
-error: Public: pub, Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
- --> $DIR/access_levels.rs:47:5
- |
-LL | macro_rules! public_macro {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: Public: pub(crate), Exported: pub(crate), Reachable: pub, ReachableFromImplTrait: pub
- --> $DIR/access_levels.rs:52:5
- |
-LL | pub struct ReachableStruct {
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: Public: pub(crate), Exported: pub(crate), Reachable: pub, ReachableFromImplTrait: pub
- --> $DIR/access_levels.rs:54:9
- |
-LL | pub a: u8,
- | ^^^^^^^^^
-
-error: Public: pub, Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
- --> $DIR/access_levels.rs:59:9
- |
-LL | pub use outer::inner1;
- | ^^^^^^^^^^^^^
-
-error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
- --> $DIR/access_levels.rs:65:5
- |
-LL | pub type HalfPublicImport = u8;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: Public: pub(crate), Exported: pub(crate), Reachable: pub(crate), ReachableFromImplTrait: pub(crate)
- --> $DIR/access_levels.rs:68:5
- |
-LL | pub(crate) const HalfPublicImport: u8 = 0;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: Public: pub, Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
- --> $DIR/access_levels.rs:72:9
- |
-LL | pub use half_public_import::HalfPublicImport;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: Public: pub, Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
- --> $DIR/access_levels.rs:72:9
- |
-LL | pub use half_public_import::HalfPublicImport;
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
- --> $DIR/access_levels.rs:14:13
- |
-LL | const A: i32;
- | ^^^^^^^^^^^^
-
-error: Public: pub(crate), Exported: pub, Reachable: pub, ReachableFromImplTrait: pub
- --> $DIR/access_levels.rs:16:13
- |
-LL | type B;
- | ^^^^^^
-
-error: aborting due to 22 previous errors
-
--- /dev/null
+#![feature(rustc_attrs)]
+
+#[rustc_effective_visibility]
+mod outer { //~ ERROR Direct: pub(crate), Reexported: pub(crate), Reachable: pub(crate), ReachableThroughImplTrait: pub(crate)
+ #[rustc_effective_visibility]
+ pub mod inner1 { //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+
+ #[rustc_effective_visibility]
+ extern "C" {} //~ ERROR not in the table
+
+ #[rustc_effective_visibility]
+ pub trait PubTrait { //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ #[rustc_effective_visibility]
+ const A: i32; //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ #[rustc_effective_visibility]
+ type B; //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ }
+
+ #[rustc_effective_visibility]
+ struct PrivStruct; //~ ERROR not in the table
+ //~| ERROR not in the table
+
+ #[rustc_effective_visibility]
+ pub union PubUnion { //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ #[rustc_effective_visibility]
+ a: u8, //~ ERROR not in the table
+ #[rustc_effective_visibility]
+ pub b: u8, //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ }
+
+ #[rustc_effective_visibility]
+ pub enum Enum { //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ #[rustc_effective_visibility]
+ A( //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ //~| ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ #[rustc_effective_visibility]
+ PubUnion, //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ ),
+ }
+ }
+
+ #[rustc_effective_visibility]
+ macro_rules! none_macro { //~ ERROR not in the table
+ () => {};
+ }
+
+ #[macro_export]
+ #[rustc_effective_visibility]
+ macro_rules! public_macro { //~ ERROR Direct: pub(self), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ () => {};
+ }
+
+ #[rustc_effective_visibility]
+ pub struct ReachableStruct { //~ ERROR Direct: pub(crate), Reexported: pub(crate), Reachable: pub, ReachableThroughImplTrait: pub
+ #[rustc_effective_visibility]
+ pub a: u8, //~ ERROR Direct: pub(crate), Reexported: pub(crate), Reachable: pub, ReachableThroughImplTrait: pub
+ }
+}
+
+#[rustc_effective_visibility]
+pub use outer::inner1; //~ ERROR Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+
+pub fn foo() -> outer::ReachableStruct { outer::ReachableStruct {a: 0} }
+
+mod half_public_import {
+ #[rustc_effective_visibility]
+ pub type HalfPublicImport = u8; //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ #[rustc_effective_visibility]
+ #[allow(non_upper_case_globals)]
+ pub(crate) const HalfPublicImport: u8 = 0; //~ ERROR Direct: pub(crate), Reexported: pub(crate), Reachable: pub(crate), ReachableThroughImplTrait: pub(crate)
+}
+
+#[rustc_effective_visibility]
+pub use half_public_import::HalfPublicImport; //~ ERROR Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ //~^ ERROR Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+
+fn main() {}
--- /dev/null
+error: Direct: pub(crate), Reexported: pub(crate), Reachable: pub(crate), ReachableThroughImplTrait: pub(crate)
+ --> $DIR/effective_visibilities.rs:4:1
+ |
+LL | mod outer {
+ | ^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ --> $DIR/effective_visibilities.rs:6:5
+ |
+LL | pub mod inner1 {
+ | ^^^^^^^^^^^^^^
+
+error: not in the table
+ --> $DIR/effective_visibilities.rs:9:9
+ |
+LL | extern "C" {}
+ | ^^^^^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ --> $DIR/effective_visibilities.rs:12:9
+ |
+LL | pub trait PubTrait {
+ | ^^^^^^^^^^^^^^^^^^
+
+error: not in the table
+ --> $DIR/effective_visibilities.rs:20:9
+ |
+LL | struct PrivStruct;
+ | ^^^^^^^^^^^^^^^^^
+
+error: not in the table
+ --> $DIR/effective_visibilities.rs:20:9
+ |
+LL | struct PrivStruct;
+ | ^^^^^^^^^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ --> $DIR/effective_visibilities.rs:24:9
+ |
+LL | pub union PubUnion {
+ | ^^^^^^^^^^^^^^^^^^
+
+error: not in the table
+ --> $DIR/effective_visibilities.rs:26:13
+ |
+LL | a: u8,
+ | ^^^^^
+
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ --> $DIR/effective_visibilities.rs:28:13
+ |
+LL | pub b: u8,
+ | ^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ --> $DIR/effective_visibilities.rs:32:9
+ |
+LL | pub enum Enum {
+ | ^^^^^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ --> $DIR/effective_visibilities.rs:34:13
+ |
+LL | A(
+ | ^
+
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ --> $DIR/effective_visibilities.rs:34:13
+ |
+LL | A(
+ | ^
+
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ --> $DIR/effective_visibilities.rs:37:17
+ |
+LL | PubUnion,
+ | ^^^^^^^^
+
+error: not in the table
+ --> $DIR/effective_visibilities.rs:43:5
+ |
+LL | macro_rules! none_macro {
+ | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Direct: pub(self), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ --> $DIR/effective_visibilities.rs:49:5
+ |
+LL | macro_rules! public_macro {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub(crate), Reachable: pub, ReachableThroughImplTrait: pub
+ --> $DIR/effective_visibilities.rs:54:5
+ |
+LL | pub struct ReachableStruct {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub(crate), Reachable: pub, ReachableThroughImplTrait: pub
+ --> $DIR/effective_visibilities.rs:56:9
+ |
+LL | pub a: u8,
+ | ^^^^^^^^^
+
+error: Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ --> $DIR/effective_visibilities.rs:61:9
+ |
+LL | pub use outer::inner1;
+ | ^^^^^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ --> $DIR/effective_visibilities.rs:67:5
+ |
+LL | pub type HalfPublicImport = u8;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub(crate), Reachable: pub(crate), ReachableThroughImplTrait: pub(crate)
+ --> $DIR/effective_visibilities.rs:70:5
+ |
+LL | pub(crate) const HalfPublicImport: u8 = 0;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ --> $DIR/effective_visibilities.rs:74:9
+ |
+LL | pub use half_public_import::HalfPublicImport;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ --> $DIR/effective_visibilities.rs:74:9
+ |
+LL | pub use half_public_import::HalfPublicImport;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ --> $DIR/effective_visibilities.rs:14:13
+ |
+LL | const A: i32;
+ | ^^^^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ --> $DIR/effective_visibilities.rs:16:13
+ |
+LL | type B;
+ | ^^^^^^
+
+error: aborting due to 24 previous errors
+
--- /dev/null
+// Effective visibility tracking for imports is fine-grained, so `S2` is not fully exported
+// even if its parent import (`m::*`) is fully exported as a `use` item.
+
+#![feature(rustc_attrs)]
+
+mod m {
+ #[rustc_effective_visibility]
+ pub struct S1 {} //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ #[rustc_effective_visibility]
+ pub struct S2 {} //~ ERROR Direct: pub(crate), Reexported: pub(crate), Reachable: pub(crate), ReachableThroughImplTrait: pub(crate)
+}
+
+mod glob {
+ #[rustc_effective_visibility]
+ pub use crate::m::*; //~ ERROR Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+}
+
+#[rustc_effective_visibility]
+pub use glob::S1; //~ ERROR Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+
+fn main() {}
--- /dev/null
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ --> $DIR/effective_visibilities_glob.rs:8:5
+ |
+LL | pub struct S1 {}
+ | ^^^^^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub(crate), Reachable: pub(crate), ReachableThroughImplTrait: pub(crate)
+ --> $DIR/effective_visibilities_glob.rs:10:5
+ |
+LL | pub struct S2 {}
+ | ^^^^^^^^^^^^^
+
+error: Direct: pub(crate), Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ --> $DIR/effective_visibilities_glob.rs:15:13
+ |
+LL | pub use crate::m::*;
+ | ^^^^^^^^
+
+error: Direct: pub, Reexported: pub, Reachable: pub, ReachableThroughImplTrait: pub
+ --> $DIR/effective_visibilities_glob.rs:19:9
+ |
+LL | pub use glob::S1;
+ | ^^^^^^^^
+
+error: aborting due to 4 previous errors
+
--> $DIR/amputate-span.rs:49:5
|
LL | Command::new("git");
- | ^^^^^^^ not found in this scope
+ | ^^^^^^^ use of undeclared type `Command`
|
help: consider importing this struct
|
--> $DIR/amputate-span.rs:63:9
|
LL | Command::new("git");
- | ^^^^^^^ not found in this scope
+ | ^^^^^^^ use of undeclared type `Command`
|
help: consider importing this struct
|
#[derive(generate_mod::CheckDerive)] //~ ERROR cannot find type `FromOutside` in this scope
//~| ERROR cannot find type `OuterDerive` in this scope
- //~| WARN this was previously accepted
- //~| WARN this was previously accepted
struct Z;
fn inner_block() {
#[derive(generate_mod::CheckDerive)] //~ ERROR cannot find type `FromOutside` in this scope
//~| ERROR cannot find type `OuterDerive` in this scope
- //~| WARN this was previously accepted
- //~| WARN this was previously accepted
struct InnerZ;
}
-#[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed
+#[derive(generate_mod::CheckDeriveLint)] //~ ERROR cannot find type `OuterDeriveLint` in this scope
+ //~| ERROR cannot find type `FromOutside` in this scope
struct W;
fn main() {}
OuterAttr
= note: this error originates in the attribute macro `generate_mod::check_attr` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: cannot find type `FromOutside` in this scope
+error[E0412]: cannot find type `FromOutside` in this scope
--> $DIR/generate-mod.rs:16:10
|
LL | #[derive(generate_mod::CheckDerive)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
- = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
+ = note: consider importing this struct:
+ FromOutside
= note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: cannot find type `OuterDerive` in this scope
+error[E0412]: cannot find type `OuterDerive` in this scope
--> $DIR/generate-mod.rs:16:10
|
LL | #[derive(generate_mod::CheckDerive)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
- = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: cannot find type `FromOutside` in this scope
- --> $DIR/generate-mod.rs:23:14
- |
-LL | #[derive(generate_mod::CheckDerive)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
+ = note: consider importing this struct:
+ OuterDerive
= note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
-error: cannot find type `OuterDerive` in this scope
- --> $DIR/generate-mod.rs:23:14
+error[E0412]: cannot find type `FromOutside` in this scope
+ --> $DIR/generate-mod.rs:21:14
|
LL | #[derive(generate_mod::CheckDerive)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
- = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 8 previous errors
-
-For more information about this error, try `rustc --explain E0412`.
-Future incompatibility report: Future breakage diagnostic:
-error: cannot find type `FromOutside` in this scope
- --> $DIR/generate-mod.rs:16:10
- |
-LL | #[derive(generate_mod::CheckDerive)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
- = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
- = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-Future breakage diagnostic:
-error: cannot find type `OuterDerive` in this scope
- --> $DIR/generate-mod.rs:16:10
- |
-LL | #[derive(generate_mod::CheckDerive)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
- = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
+ = note: consider importing this struct:
+ FromOutside
= note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
-Future breakage diagnostic:
-error: cannot find type `FromOutside` in this scope
- --> $DIR/generate-mod.rs:23:14
+error[E0412]: cannot find type `OuterDerive` in this scope
+ --> $DIR/generate-mod.rs:21:14
|
LL | #[derive(generate_mod::CheckDerive)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
- = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
+ = note: consider importing this struct:
+ OuterDerive
= note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
-Future breakage diagnostic:
-error: cannot find type `OuterDerive` in this scope
- --> $DIR/generate-mod.rs:23:14
+error[E0412]: cannot find type `FromOutside` in this scope
+ --> $DIR/generate-mod.rs:26:10
|
-LL | #[derive(generate_mod::CheckDerive)]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
+LL | #[derive(generate_mod::CheckDeriveLint)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
- = note: `#[deny(proc_macro_derive_resolution_fallback)]` on by default
- = note: this error originates in the derive macro `generate_mod::CheckDerive` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: consider importing this struct:
+ FromOutside
+ = note: this error originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info)
-Future breakage diagnostic:
-warning: cannot find type `FromOutside` in this scope
- --> $DIR/generate-mod.rs:30:10
+error[E0412]: cannot find type `OuterDeriveLint` in this scope
+ --> $DIR/generate-mod.rs:26:10
|
-LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
+LL | #[derive(generate_mod::CheckDeriveLint)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope
|
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
-note: the lint level is defined here
- --> $DIR/generate-mod.rs:30:10
- |
-LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = note: this warning originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info)
+ = note: consider importing this struct:
+ OuterDeriveLint
+ = note: this error originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info)
-Future breakage diagnostic:
-warning: cannot find type `OuterDeriveLint` in this scope
- --> $DIR/generate-mod.rs:30:10
- |
-LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
- |
- = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
- = note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
-note: the lint level is defined here
- --> $DIR/generate-mod.rs:30:10
- |
-LL | #[derive(generate_mod::CheckDeriveLint)] // OK, lint is suppressed
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- = note: this warning originates in the derive macro `generate_mod::CheckDeriveLint` (in Nightly builds, run with -Z macro-backtrace for more info)
+error: aborting due to 10 previous errors
+For more information about this error, try `rustc --explain E0412`.
--- /dev/null
+// run-pass
+
+#![allow(stable_features)]
+#![allow(unused_variables)]
+
+// #45662
+
+#![feature(repr_align)]
+
+#[repr(align(16))]
+pub struct A(#[allow(unused_tuple_struct_fields)] i64);
+
+#[allow(improper_ctypes_definitions)]
+pub extern "C" fn foo(x: A) {}
+
+fn main() {
+ foo(A(0));
+}
--- /dev/null
+// run-pass
+// allows aligned custom discriminant enums to cast into other types
+// See the issue #92464 for more info
+#[allow(dead_code)]
+#[repr(align(8))]
+enum Aligned {
+ Zero = 0,
+ One = 1,
+}
+
+fn main() {
+ let aligned = Aligned::Zero;
+ let fo = aligned as u8;
+ println!("foo {}", fo);
+ assert_eq!(fo, 0);
+ println!("{}", tou8(Aligned::Zero));
+ assert_eq!(tou8(Aligned::Zero), 0);
+}
+
+#[inline(never)]
+fn tou8(al: Aligned) -> u8 {
+ // Cast behind a function call so ConstProp does not see it
+ // (so that we can test codegen).
+ al as u8
+}
--- /dev/null
+// run-pass
+// compile-flags: -O
+
+#![allow(dead_code)]
+
+#[repr(C, u8)]
+enum ReprCu8 {
+ A(u16),
+ B,
+}
+
+#[repr(u8)]
+enum Repru8 {
+ A(u16),
+ B,
+}
+
+#[repr(C)]
+struct ReprC {
+ tag: u8,
+ padding: u8,
+ payload: u16,
+}
+
+fn main() {
+ // Test `repr(C, u8)`.
+ let r1 = ReprC { tag: 0, padding: 0, payload: 0 };
+ let r2 = ReprC { tag: 0, padding: 1, payload: 1 };
+
+ let t1: &ReprCu8 = unsafe { std::mem::transmute(&r1) };
+ let t2: &ReprCu8 = unsafe { std::mem::transmute(&r2) };
+
+ match (t1, t2) {
+ (ReprCu8::A(_), ReprCu8::A(_)) => (),
+ _ => assert!(false)
+ };
+
+ // Test `repr(u8)`.
+ let t1: &Repru8 = unsafe { std::mem::transmute(&r1) };
+ let t2: &Repru8 = unsafe { std::mem::transmute(&r2) };
+
+ match (t1, t2) {
+ (Repru8::A(_), Repru8::A(_)) => (),
+ _ => assert!(false)
+ };
+}
+++ /dev/null
-// run-pass
-// compile-flags: -O
-
-#![allow(dead_code)]
-
-#[repr(C, u8)]
-enum ReprCu8 {
- A(u16),
- B,
-}
-
-#[repr(u8)]
-enum Repru8 {
- A(u16),
- B,
-}
-
-#[repr(C)]
-struct ReprC {
- tag: u8,
- padding: u8,
- payload: u16,
-}
-
-fn main() {
- // Test `repr(C, u8)`.
- let r1 = ReprC { tag: 0, padding: 0, payload: 0 };
- let r2 = ReprC { tag: 0, padding: 1, payload: 1 };
-
- let t1: &ReprCu8 = unsafe { std::mem::transmute(&r1) };
- let t2: &ReprCu8 = unsafe { std::mem::transmute(&r2) };
-
- match (t1, t2) {
- (ReprCu8::A(_), ReprCu8::A(_)) => (),
- _ => assert!(false)
- };
-
- // Test `repr(u8)`.
- let t1: &Repru8 = unsafe { std::mem::transmute(&r1) };
- let t2: &Repru8 = unsafe { std::mem::transmute(&r2) };
-
- match (t1, t2) {
- (Repru8::A(_), Repru8::A(_)) => (),
- _ => assert!(false)
- };
-}
}
impl dyn ToNbt<Self> {}
-//~^ ERROR cycle detected
+//~^ ERROR `Self` is not valid in the self type of an impl block
fn main() {}
-error[E0391]: cycle detected when computing type of `<impl at $DIR/issue-23305.rs:5:1: 5:21>`
+error: `Self` is not valid in the self type of an impl block
--> $DIR/issue-23305.rs:5:16
|
LL | impl dyn ToNbt<Self> {}
| ^^^^
|
- = note: ...which immediately requires computing type of `<impl at $DIR/issue-23305.rs:5:1: 5:21>` again
-note: cycle used when collecting item types in top-level module
- --> $DIR/issue-23305.rs:1:1
- |
-LL | / pub trait ToNbt<T> {
-LL | | fn new(val: T) -> Self;
-LL | | }
-LL | |
-... |
-LL | |
-LL | | fn main() {}
- | |____________^
+ = note: replace `Self` with a different type
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0391`.
error[E0433]: failed to resolve: could not find `hahmap` in `std`
- --> $DIR/missing-in-namespace.rs:2:29
+ --> $DIR/missing-in-namespace.rs:2:21
|
LL | let _map = std::hahmap::HashMap::new();
- | ^^^^^^^ not found in `std::hahmap`
+ | ^^^^^^ could not find `hahmap` in `std`
|
help: consider importing this struct
|
error[E0574]: expected struct, variant or union type, found type parameter `Baz`
--> $DIR/point-at-type-parameter-shadowing-another-type.rs:16:13
|
-LL | / struct Baz {
-LL | | num: usize,
-LL | | }
- | |_- you might have meant to refer to this struct
-LL |
-LL | impl<Baz> Foo<Baz> for Bar {
- | --- found this type parameter
+LL | struct Baz {
+ | --- you might have meant to refer to this struct
...
-LL | Baz { num } => num,
- | ^^^ not a struct, variant or union type
+LL | impl<Baz> Foo<Baz> for Bar {
+ | --- found this type parameter
+...
+LL | Baz { num } => num,
+ | ^^^ not a struct, variant or union type
error: aborting due to previous error
impl Tr for S where S<Self>: Copy {} // OK
impl Tr for S where Self::A: Copy {} // OK
-impl Tr for Self {} //~ ERROR cycle detected
-impl Tr for S<Self> {} //~ ERROR cycle detected
-impl Self {} //~ ERROR cycle detected
-impl S<Self> {} //~ ERROR cycle detected
+impl Tr for Self {} //~ ERROR `Self` is not valid in the self type of an impl block
+impl Tr for S<Self> {} //~ ERROR `Self` is not valid in the self type of an impl block
+impl Self {} //~ ERROR `Self` is not valid in the self type of an impl block
+impl S<Self> {} //~ ERROR `Self` is not valid in the self type of an impl block
+impl (Self, Self) {} //~ ERROR `Self` is not valid in the self type of an impl block
impl Tr<Self::A> for S {} //~ ERROR cycle detected
fn main() {}
-error[E0391]: cycle detected when computing type of `<impl at $DIR/resolve-self-in-impl.rs:14:1: 14:17>`
- --> $DIR/resolve-self-in-impl.rs:14:13
- |
-LL | impl Tr for Self {}
- | ^^^^
- |
- = note: ...which immediately requires computing type of `<impl at $DIR/resolve-self-in-impl.rs:14:1: 14:17>` again
-note: cycle used when collecting item types in top-level module
- --> $DIR/resolve-self-in-impl.rs:1:1
- |
-LL | / #![feature(associated_type_defaults)]
-LL | |
-LL | | struct S<T = u8>(T);
-LL | | trait Tr<T = u8> {
-... |
-LL | |
-LL | | fn main() {}
- | |____________^
-
-error[E0391]: cycle detected when computing type of `<impl at $DIR/resolve-self-in-impl.rs:15:1: 15:20>`
- --> $DIR/resolve-self-in-impl.rs:15:15
- |
-LL | impl Tr for S<Self> {}
- | ^^^^
- |
- = note: ...which immediately requires computing type of `<impl at $DIR/resolve-self-in-impl.rs:15:1: 15:20>` again
-note: cycle used when collecting item types in top-level module
- --> $DIR/resolve-self-in-impl.rs:1:1
- |
-LL | / #![feature(associated_type_defaults)]
-LL | |
-LL | | struct S<T = u8>(T);
-LL | | trait Tr<T = u8> {
-... |
-LL | |
-LL | | fn main() {}
- | |____________^
-
-error[E0391]: cycle detected when computing type of `<impl at $DIR/resolve-self-in-impl.rs:16:1: 16:10>`
+error: `Self` is not valid in the self type of an impl block
--> $DIR/resolve-self-in-impl.rs:16:6
|
LL | impl Self {}
| ^^^^
|
- = note: ...which immediately requires computing type of `<impl at $DIR/resolve-self-in-impl.rs:16:1: 16:10>` again
-note: cycle used when collecting item types in top-level module
- --> $DIR/resolve-self-in-impl.rs:1:1
- |
-LL | / #![feature(associated_type_defaults)]
-LL | |
-LL | | struct S<T = u8>(T);
-LL | | trait Tr<T = u8> {
-... |
-LL | |
-LL | | fn main() {}
- | |____________^
+ = note: replace `Self` with a different type
-error[E0391]: cycle detected when computing type of `<impl at $DIR/resolve-self-in-impl.rs:17:1: 17:13>`
+error: `Self` is not valid in the self type of an impl block
--> $DIR/resolve-self-in-impl.rs:17:8
|
LL | impl S<Self> {}
| ^^^^
|
- = note: ...which immediately requires computing type of `<impl at $DIR/resolve-self-in-impl.rs:17:1: 17:13>` again
-note: cycle used when collecting item types in top-level module
- --> $DIR/resolve-self-in-impl.rs:1:1
+ = note: replace `Self` with a different type
+
+error: `Self` is not valid in the self type of an impl block
+ --> $DIR/resolve-self-in-impl.rs:18:7
|
-LL | / #![feature(associated_type_defaults)]
-LL | |
-LL | | struct S<T = u8>(T);
-LL | | trait Tr<T = u8> {
-... |
-LL | |
-LL | | fn main() {}
- | |____________^
+LL | impl (Self, Self) {}
+ | ^^^^ ^^^^
+ |
+ = note: replace `Self` with a different type
+
+error: `Self` is not valid in the self type of an impl block
+ --> $DIR/resolve-self-in-impl.rs:14:13
+ |
+LL | impl Tr for Self {}
+ | ^^^^
+ |
+ = note: replace `Self` with a different type
+
+error: `Self` is not valid in the self type of an impl block
+ --> $DIR/resolve-self-in-impl.rs:15:15
+ |
+LL | impl Tr for S<Self> {}
+ | ^^^^
+ |
+ = note: replace `Self` with a different type
-error[E0391]: cycle detected when computing trait implemented by `<impl at $DIR/resolve-self-in-impl.rs:18:1: 18:23>`
- --> $DIR/resolve-self-in-impl.rs:18:1
+error[E0391]: cycle detected when computing trait implemented by `<impl at $DIR/resolve-self-in-impl.rs:19:1: 19:23>`
+ --> $DIR/resolve-self-in-impl.rs:19:1
|
LL | impl Tr<Self::A> for S {}
| ^^^^^^^^^^^^^^^^^^^^^^
|
- = note: ...which immediately requires computing trait implemented by `<impl at $DIR/resolve-self-in-impl.rs:18:1: 18:23>` again
+ = note: ...which immediately requires computing trait implemented by `<impl at $DIR/resolve-self-in-impl.rs:19:1: 19:23>` again
note: cycle used when collecting item types in top-level module
--> $DIR/resolve-self-in-impl.rs:1:1
|
LL | | fn main() {}
| |____________^
-error: aborting due to 5 previous errors
+error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0391`.
--- /dev/null
+struct Struct;
+//~^ NOTE function or associated item `fob` not found for this struct
+
+impl Struct {
+ fn foo() { }
+}
+
+mod module {
+ fn foo() { }
+
+ struct Struct;
+
+ impl Struct {
+ fn foo() { }
+ }
+}
+
+trait Trait {
+ fn foo();
+}
+
+fn main() {
+ Struct::fob();
+ //~^ ERROR no function or associated item named `fob` found for struct `Struct` in the current scope
+ //~| NOTE function or associated item not found in `Struct`
+
+ Struc::foo();
+ //~^ ERROR failed to resolve: use of undeclared type `Struc`
+ //~| NOTE use of undeclared type `Struc`
+
+ modul::foo();
+ //~^ ERROR failed to resolve: use of undeclared crate or module `modul`
+ //~| NOTE use of undeclared crate or module `modul`
+
+ module::Struc::foo();
+ //~^ ERROR failed to resolve: could not find `Struc` in `module`
+ //~| NOTE could not find `Struc` in `module`
+
+ Trai::foo();
+ //~^ ERROR failed to resolve: use of undeclared type `Trai`
+ //~| NOTE use of undeclared type `Trai`
+}
--- /dev/null
+error[E0433]: failed to resolve: use of undeclared type `Struc`
+ --> $DIR/typo-suggestion-mistyped-in-path.rs:27:5
+ |
+LL | Struc::foo();
+ | ^^^^^
+ | |
+ | use of undeclared type `Struc`
+ | help: a struct with a similar name exists: `Struct`
+
+error[E0433]: failed to resolve: use of undeclared crate or module `modul`
+ --> $DIR/typo-suggestion-mistyped-in-path.rs:31:5
+ |
+LL | modul::foo();
+ | ^^^^^ use of undeclared crate or module `modul`
+ |
+help: there is a crate or module with a similar name
+ |
+LL | module::foo();
+ | ~~~~~~
+
+error[E0433]: failed to resolve: could not find `Struc` in `module`
+ --> $DIR/typo-suggestion-mistyped-in-path.rs:35:13
+ |
+LL | module::Struc::foo();
+ | ^^^^^
+ | |
+ | could not find `Struc` in `module`
+ | help: a struct with a similar name exists: `Struct`
+
+error[E0433]: failed to resolve: use of undeclared type `Trai`
+ --> $DIR/typo-suggestion-mistyped-in-path.rs:39:5
+ |
+LL | Trai::foo();
+ | ^^^^
+ | |
+ | use of undeclared type `Trai`
+ | help: a trait with a similar name exists: `Trait`
+
+error[E0599]: no function or associated item named `fob` found for struct `Struct` in the current scope
+ --> $DIR/typo-suggestion-mistyped-in-path.rs:23:13
+ |
+LL | struct Struct;
+ | ------------- function or associated item `fob` not found for this struct
+...
+LL | Struct::fob();
+ | ^^^
+ | |
+ | function or associated item not found in `Struct`
+ | help: there is an associated function with a similar name: `foo`
+
+error: aborting due to 5 previous errors
+
+Some errors have detailed explanations: E0433, E0599.
+For more information about an error, try `rustc --explain E0433`.
--> $DIR/use_suggestion.rs:2:14
|
LL | let x1 = HashMap::new();
- | ^^^^^^^ not found in this scope
+ | ^^^^^^^ use of undeclared type `HashMap`
|
help: consider importing this struct
|
--- /dev/null
+// check-pass
+
+const _: fn(&String) = |s| { &*s as &str; };
+
+fn main() {}
error: ~const can only be applied to `#[const_trait]` traits
- --> $DIR/super-traits-fail-2.rs:11:12
+ --> $DIR/super-traits-fail-2.rs:11:19
|
LL | trait Bar: ~const Foo {}
- | ^^^^^^^^^^
+ | ^^^
error: aborting due to previous error
error: ~const can only be applied to `#[const_trait]` traits
- --> $DIR/super-traits-fail-2.rs:11:12
+ --> $DIR/super-traits-fail-2.rs:11:19
|
LL | trait Bar: ~const Foo {}
- | ^^^^^^^^^^
+ | ^^^
error: aborting due to previous error
error: ~const can only be applied to `#[const_trait]` traits
- --> $DIR/super-traits-fail-3.rs:12:12
+ --> $DIR/super-traits-fail-3.rs:12:19
|
LL | trait Bar: ~const Foo {}
- | ^^^^^^^^^^
+ | ^^^
error: ~const can only be applied to `#[const_trait]` traits
- --> $DIR/super-traits-fail-3.rs:15:17
+ --> $DIR/super-traits-fail-3.rs:15:24
|
LL | const fn foo<T: ~const Bar>(x: &T) {
- | ^^^^^^^^^^
+ | ^^^
error: aborting due to 2 previous errors
error: ~const can only be applied to `#[const_trait]` traits
- --> $DIR/super-traits-fail-3.rs:12:12
+ --> $DIR/super-traits-fail-3.rs:12:19
|
LL | trait Bar: ~const Foo {}
- | ^^^^^^^^^^
+ | ^^^
error: aborting due to previous error
error: ~const can only be applied to `#[const_trait]` traits
- --> $DIR/super-traits-fail-3.rs:15:17
+ --> $DIR/super-traits-fail-3.rs:15:24
|
LL | const fn foo<T: ~const Bar>(x: &T) {
- | ^^^^^^^^^^
+ | ^^^
error: aborting due to previous error
+++ /dev/null
-#![allow(dead_code)]
-
-fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 {
- a
-}
-
-// the boundaries of elision
-static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 =
-//~^ ERROR missing lifetime specifier [E0106]
- &(non_elidable as fn(&u8, &u8) -> &u8);
- //~^ ERROR missing lifetime specifier [E0106]
- //~| ERROR non-primitive cast
-
-fn main() {}
+++ /dev/null
-error[E0106]: missing lifetime specifier
- --> $DIR/rfc1623-2.rs:8:42
- |
-LL | static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 =
- | --- --- ^ expected named lifetime parameter
- |
- = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2
- = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
-help: consider making the type lifetime-generic with a new `'a` lifetime
- |
-LL | static NON_ELIDABLE_FN: &for<'a> fn(&'a u8, &'a u8) -> &'a u8 =
- | +++++++ ++ ++ ++
-
-error[E0106]: missing lifetime specifier
- --> $DIR/rfc1623-2.rs:10:39
- |
-LL | &(non_elidable as fn(&u8, &u8) -> &u8);
- | --- --- ^ expected named lifetime parameter
- |
- = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2
-help: consider making the type lifetime-generic with a new `'a` lifetime
- |
-LL | &(non_elidable as for<'a> fn(&'a u8, &'a u8) -> &'a u8);
- | +++++++ ++ ++ ++
-
-error[E0605]: non-primitive cast: `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8 {non_elidable}` as `for<'a, 'b> fn(&'a u8, &'b u8) -> &u8`
- --> $DIR/rfc1623-2.rs:10:6
- |
-LL | &(non_elidable as fn(&u8, &u8) -> &u8);
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
-
-error: aborting due to 3 previous errors
-
-Some errors have detailed explanations: E0106, E0605.
-For more information about an error, try `rustc --explain E0106`.
+++ /dev/null
-#![allow(dead_code)]
-
-fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 {
- a
-}
-
-// The incorrect case without `for<'a>` is tested for in `rfc1623-2.rs`
-static NON_ELIDABLE_FN: &for<'a> fn(&'a u8, &'a u8) -> &'a u8 =
- &(non_elidable as for<'a> fn(&'a u8, &'a u8) -> &'a u8);
-
-struct SomeStruct<'x, 'y, 'z: 'x> {
- foo: &'x Foo<'z>,
- bar: &'x Bar<'z>,
- f: &'y dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>,
-}
-
-// Without this, the wf-check will fail early so we'll never see the
-// error in SOME_STRUCT's body.
-unsafe impl<'x, 'y, 'z: 'x> Sync for SomeStruct<'x, 'y, 'z> {}
-
-fn id<T>(t: T) -> T {
- t
-}
-
-static SOME_STRUCT: &SomeStruct = &SomeStruct {
- foo: &Foo { bools: &[false, true] },
- bar: &Bar { bools: &[true, true] },
- f: &id,
- //~^ ERROR mismatched types
- //~| ERROR mismatched types
- //~| ERROR implementation of `FnOnce` is not general enough
- //~| ERROR implementation of `FnOnce` is not general enough
-};
-
-// very simple test for a 'static static with default lifetime
-static STATIC_STR: &'static str = "&'static str";
-const CONST_STR: &'static str = "&'static str";
-
-// this should be the same as without default:
-static EXPLICIT_STATIC_STR: &'static str = "&'static str";
-const EXPLICIT_CONST_STR: &'static str = "&'static str";
-
-// a function that elides to an unbound lifetime for both in- and output
-fn id_u8_slice(arg: &[u8]) -> &[u8] {
- arg
-}
-
-// one with a function, argument elided
-static STATIC_SIMPLE_FN: &'static fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]);
-const CONST_SIMPLE_FN: &'static fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]);
-
-// this should be the same as without elision
-static STATIC_NON_ELIDED_fN: &'static for<'a> fn(&'a [u8]) -> &'a [u8] =
- &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]);
-const CONST_NON_ELIDED_fN: &'static for<'a> fn(&'a [u8]) -> &'a [u8] =
- &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]);
-
-// another function that elides, each to a different unbound lifetime
-fn multi_args(a: &u8, b: &u8, c: &u8) {}
-
-static STATIC_MULTI_FN: &'static fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8));
-const CONST_MULTI_FN: &'static fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8));
-
-struct Foo<'a> {
- bools: &'a [bool],
-}
-
-static STATIC_FOO: Foo<'static> = Foo { bools: &[true, false] };
-const CONST_FOO: Foo<'static> = Foo { bools: &[true, false] };
-
-type Bar<'a> = Foo<'a>;
-
-static STATIC_BAR: Bar<'static> = Bar { bools: &[true, false] };
-const CONST_BAR: Bar<'static> = Bar { bools: &[true, false] };
-
-type Baz<'a> = fn(&'a [u8]) -> Option<u8>;
-
-fn baz(e: &[u8]) -> Option<u8> {
- e.first().map(|x| *x)
-}
-
-static STATIC_BAZ: &'static Baz<'static> = &(baz as Baz);
-const CONST_BAZ: &'static Baz<'static> = &(baz as Baz);
-
-static BYTES: &'static [u8] = &[1, 2, 3];
-
-fn main() {
- let x = &[1u8, 2, 3];
- let y = x;
-
- // this works, so lifetime < `'static` is valid
- assert_eq!(Some(1), STATIC_BAZ(y));
- assert_eq!(Some(1), CONST_BAZ(y));
-
- let y = &[1u8, 2, 3];
-
- STATIC_BAZ(BYTES); // BYTES has static lifetime
- CONST_BAZ(y); // interestingly this does not get reported
-}
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/rfc1623.rs:28:8
- |
-LL | f: &id,
- | ^^^ one type is more general than the other
- |
- = note: expected trait `for<'a, 'b> Fn<(&'a Foo<'b>,)>`
- found trait `Fn<(&Foo<'_>,)>`
-
-error[E0308]: mismatched types
- --> $DIR/rfc1623.rs:28:8
- |
-LL | f: &id,
- | ^^^ one type is more general than the other
- |
- = note: expected trait `for<'a, 'b> Fn<(&'a Foo<'b>,)>`
- found trait `Fn<(&Foo<'_>,)>`
-
-error: implementation of `FnOnce` is not general enough
- --> $DIR/rfc1623.rs:28:8
- |
-LL | f: &id,
- | ^^^ implementation of `FnOnce` is not general enough
- |
- = note: `fn(&'2 Foo<'_>) -> &'2 Foo<'_> {id::<&'2 Foo<'_>>}` must implement `FnOnce<(&'1 Foo<'b>,)>`, for any lifetime `'1`...
- = note: ...but it actually implements `FnOnce<(&'2 Foo<'_>,)>`, for some specific lifetime `'2`
-
-error: implementation of `FnOnce` is not general enough
- --> $DIR/rfc1623.rs:28:8
- |
-LL | f: &id,
- | ^^^ implementation of `FnOnce` is not general enough
- |
- = note: `fn(&Foo<'2>) -> &Foo<'2> {id::<&Foo<'2>>}` must implement `FnOnce<(&'a Foo<'1>,)>`, for any lifetime `'1`...
- = note: ...but it actually implements `FnOnce<(&Foo<'2>,)>`, for some specific lifetime `'2`
-
-error: aborting due to 4 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+#![allow(dead_code)]
+
+fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 {
+ a
+}
+
+// The incorrect case without `for<'a>` is tested for in `rfc1623-2.rs`
+static NON_ELIDABLE_FN: &for<'a> fn(&'a u8, &'a u8) -> &'a u8 =
+ &(non_elidable as for<'a> fn(&'a u8, &'a u8) -> &'a u8);
+
+struct SomeStruct<'x, 'y, 'z: 'x> {
+ foo: &'x Foo<'z>,
+ bar: &'x Bar<'z>,
+ f: &'y dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>,
+}
+
+// Without this, the wf-check will fail early so we'll never see the
+// error in SOME_STRUCT's body.
+unsafe impl<'x, 'y, 'z: 'x> Sync for SomeStruct<'x, 'y, 'z> {}
+
+fn id<T>(t: T) -> T {
+ t
+}
+
+static SOME_STRUCT: &SomeStruct = &SomeStruct {
+ foo: &Foo { bools: &[false, true] },
+ bar: &Bar { bools: &[true, true] },
+ f: &id,
+ //~^ ERROR mismatched types
+ //~| ERROR mismatched types
+ //~| ERROR implementation of `FnOnce` is not general enough
+ //~| ERROR implementation of `FnOnce` is not general enough
+};
+
+// very simple test for a 'static static with default lifetime
+static STATIC_STR: &'static str = "&'static str";
+const CONST_STR: &'static str = "&'static str";
+
+// this should be the same as without default:
+static EXPLICIT_STATIC_STR: &'static str = "&'static str";
+const EXPLICIT_CONST_STR: &'static str = "&'static str";
+
+// a function that elides to an unbound lifetime for both in- and output
+fn id_u8_slice(arg: &[u8]) -> &[u8] {
+ arg
+}
+
+// one with a function, argument elided
+static STATIC_SIMPLE_FN: &'static fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]);
+const CONST_SIMPLE_FN: &'static fn(&[u8]) -> &[u8] = &(id_u8_slice as fn(&[u8]) -> &[u8]);
+
+// this should be the same as without elision
+static STATIC_NON_ELIDED_fN: &'static for<'a> fn(&'a [u8]) -> &'a [u8] =
+ &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]);
+const CONST_NON_ELIDED_fN: &'static for<'a> fn(&'a [u8]) -> &'a [u8] =
+ &(id_u8_slice as for<'a> fn(&'a [u8]) -> &'a [u8]);
+
+// another function that elides, each to a different unbound lifetime
+fn multi_args(a: &u8, b: &u8, c: &u8) {}
+
+static STATIC_MULTI_FN: &'static fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8));
+const CONST_MULTI_FN: &'static fn(&u8, &u8, &u8) = &(multi_args as fn(&u8, &u8, &u8));
+
+struct Foo<'a> {
+ bools: &'a [bool],
+}
+
+static STATIC_FOO: Foo<'static> = Foo { bools: &[true, false] };
+const CONST_FOO: Foo<'static> = Foo { bools: &[true, false] };
+
+type Bar<'a> = Foo<'a>;
+
+static STATIC_BAR: Bar<'static> = Bar { bools: &[true, false] };
+const CONST_BAR: Bar<'static> = Bar { bools: &[true, false] };
+
+type Baz<'a> = fn(&'a [u8]) -> Option<u8>;
+
+fn baz(e: &[u8]) -> Option<u8> {
+ e.first().map(|x| *x)
+}
+
+static STATIC_BAZ: &'static Baz<'static> = &(baz as Baz);
+const CONST_BAZ: &'static Baz<'static> = &(baz as Baz);
+
+static BYTES: &'static [u8] = &[1, 2, 3];
+
+fn main() {
+ let x = &[1u8, 2, 3];
+ let y = x;
+
+ // this works, so lifetime < `'static` is valid
+ assert_eq!(Some(1), STATIC_BAZ(y));
+ assert_eq!(Some(1), CONST_BAZ(y));
+
+ let y = &[1u8, 2, 3];
+
+ STATIC_BAZ(BYTES); // BYTES has static lifetime
+ CONST_BAZ(y); // interestingly this does not get reported
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/rfc1623-2.rs:28:8
+ |
+LL | f: &id,
+ | ^^^ one type is more general than the other
+ |
+ = note: expected trait `for<'a, 'b> Fn<(&'a Foo<'b>,)>`
+ found trait `Fn<(&Foo<'_>,)>`
+
+error[E0308]: mismatched types
+ --> $DIR/rfc1623-2.rs:28:8
+ |
+LL | f: &id,
+ | ^^^ one type is more general than the other
+ |
+ = note: expected trait `for<'a, 'b> Fn<(&'a Foo<'b>,)>`
+ found trait `Fn<(&Foo<'_>,)>`
+
+error: implementation of `FnOnce` is not general enough
+ --> $DIR/rfc1623-2.rs:28:8
+ |
+LL | f: &id,
+ | ^^^ implementation of `FnOnce` is not general enough
+ |
+ = note: `fn(&'2 Foo<'_>) -> &'2 Foo<'_> {id::<&'2 Foo<'_>>}` must implement `FnOnce<(&'1 Foo<'b>,)>`, for any lifetime `'1`...
+ = note: ...but it actually implements `FnOnce<(&'2 Foo<'_>,)>`, for some specific lifetime `'2`
+
+error: implementation of `FnOnce` is not general enough
+ --> $DIR/rfc1623-2.rs:28:8
+ |
+LL | f: &id,
+ | ^^^ implementation of `FnOnce` is not general enough
+ |
+ = note: `fn(&Foo<'2>) -> &Foo<'2> {id::<&Foo<'2>>}` must implement `FnOnce<(&'a Foo<'1>,)>`, for any lifetime `'1`...
+ = note: ...but it actually implements `FnOnce<(&Foo<'2>,)>`, for some specific lifetime `'2`
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+#![allow(dead_code)]
+
+fn non_elidable<'a, 'b>(a: &'a u8, b: &'b u8) -> &'a u8 {
+ a
+}
+
+// the boundaries of elision
+static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 =
+//~^ ERROR missing lifetime specifier [E0106]
+ &(non_elidable as fn(&u8, &u8) -> &u8);
+ //~^ ERROR missing lifetime specifier [E0106]
+ //~| ERROR non-primitive cast
+
+fn main() {}
--- /dev/null
+error[E0106]: missing lifetime specifier
+ --> $DIR/rfc1623-3.rs:8:42
+ |
+LL | static NON_ELIDABLE_FN: &fn(&u8, &u8) -> &u8 =
+ | --- --- ^ expected named lifetime parameter
+ |
+ = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2
+ = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the type lifetime-generic with a new `'a` lifetime
+ |
+LL | static NON_ELIDABLE_FN: &for<'a> fn(&'a u8, &'a u8) -> &'a u8 =
+ | +++++++ ++ ++ ++
+
+error[E0106]: missing lifetime specifier
+ --> $DIR/rfc1623-3.rs:10:39
+ |
+LL | &(non_elidable as fn(&u8, &u8) -> &u8);
+ | --- --- ^ expected named lifetime parameter
+ |
+ = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from argument 1 or argument 2
+help: consider making the type lifetime-generic with a new `'a` lifetime
+ |
+LL | &(non_elidable as for<'a> fn(&'a u8, &'a u8) -> &'a u8);
+ | +++++++ ++ ++ ++
+
+error[E0605]: non-primitive cast: `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8 {non_elidable}` as `for<'a, 'b> fn(&'a u8, &'b u8) -> &u8`
+ --> $DIR/rfc1623-3.rs:10:6
+ |
+LL | &(non_elidable as fn(&u8, &u8) -> &u8);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0106, E0605.
+For more information about an error, try `rustc --explain E0106`.
LL | type Future = impl Trait;
| ^^^^^^^^^^
|
- = note: `Future` must be used in combination with a concrete type within the same module
+ = note: `Future` must be used in combination with a concrete type within the same impl
error: aborting due to previous error
-#![feature(unboxed_closures)]
+#![feature(unboxed_closures, tuple_trait)]
-fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
+fn to_fn_once<A:std::marker::Tuple,F:FnOnce<A>>(f: F) -> F { f }
fn main() {
let r = {
error[E0404]: expected trait, found type parameter `Add`
--> $DIR/issue-35987.rs:5:21
|
+LL | use std::ops::Add;
+ | --- you might have meant to refer to this trait
+LL |
LL | impl<T: Clone, Add> Add for Foo<T> {
| --- ^^^ not a trait
| |
--> $DIR/core-std-import-order-issue-83564.rs:8:14
|
LL | let _x = NonZeroU32::new(5).unwrap();
- | ^^^^^^^^^^ not found in this scope
+ | ^^^^^^^^^^ use of undeclared type `NonZeroU32`
|
help: consider importing one of these items
|
--- /dev/null
+trait Trait {
+ fn func() {}
+}
+
+impl Trait for i32 {}
+
+fn main() {
+ let x: i32 = 123;
+ x.func(); //~ERROR no method
+}
--- /dev/null
+error[E0599]: no method named `func` found for type `i32` in the current scope
+ --> $DIR/issue-102354.rs:9:7
+ |
+LL | x.func();
+ | ^^^^ this is an associated function, not a method
+ |
+ = note: found the following associated functions; to be used as methods, functions must have a `self` parameter
+note: the candidate is defined in the trait `Trait`
+ --> $DIR/issue-102354.rs:2:5
+ |
+LL | fn func() {}
+ | ^^^^^^^^^
+help: use associated function syntax instead
+ |
+LL | i32::func();
+ | ~~~~~~~~~
+help: disambiguate the associated function for the candidate
+ |
+LL | <i32 as Trait>::func(x);
+ | ~~~~~~~~~~~~~~~~~~~~~~~
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0599`.
let _i: i16 = TryFrom::try_from(0_i32).unwrap();
//~^ ERROR failed to resolve: use of undeclared type
- //~| NOTE not found in this scope
+ //~| NOTE use of undeclared type
//~| NOTE 'std::convert::TryFrom' is included in the prelude starting in Edition 2021
//~| NOTE 'core::convert::TryFrom' is included in the prelude starting in Edition 2021
let _i: i16 = TryInto::try_into(0_i32).unwrap();
//~^ ERROR failed to resolve: use of undeclared type
- //~| NOTE not found in this scope
+ //~| NOTE use of undeclared type
//~| NOTE 'std::convert::TryInto' is included in the prelude starting in Edition 2021
//~| NOTE 'core::convert::TryInto' is included in the prelude starting in Edition 2021
let _v: Vec<_> = FromIterator::from_iter(&[1]);
//~^ ERROR failed to resolve: use of undeclared type
+ //~| NOTE use of undeclared type
//~| NOTE 'std::iter::FromIterator' is included in the prelude starting in Edition 2021
//~| NOTE 'core::iter::FromIterator' is included in the prelude starting in Edition 2021
}
--> $DIR/suggest-tryinto-edition-change.rs:11:19
|
LL | let _i: i16 = TryFrom::try_from(0_i32).unwrap();
- | ^^^^^^^ not found in this scope
+ | ^^^^^^^ use of undeclared type `TryFrom`
|
= note: 'std::convert::TryFrom' is included in the prelude starting in Edition 2021
= note: 'core::convert::TryFrom' is included in the prelude starting in Edition 2021
--> $DIR/suggest-tryinto-edition-change.rs:17:19
|
LL | let _i: i16 = TryInto::try_into(0_i32).unwrap();
- | ^^^^^^^ not found in this scope
+ | ^^^^^^^ use of undeclared type `TryInto`
|
= note: 'std::convert::TryInto' is included in the prelude starting in Edition 2021
= note: 'core::convert::TryInto' is included in the prelude starting in Edition 2021
--> $DIR/suggest-tryinto-edition-change.rs:23:22
|
LL | let _v: Vec<_> = FromIterator::from_iter(&[1]);
- | ^^^^^^^^^^^^
- |
- ::: $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL
- |
-LL | pub trait IntoIterator {
- | ---------------------- similarly named trait `IntoIterator` defined here
+ | ^^^^^^^^^^^^ use of undeclared type `FromIterator`
|
= note: 'std::iter::FromIterator' is included in the prelude starting in Edition 2021
= note: 'core::iter::FromIterator' is included in the prelude starting in Edition 2021
fie
foe
fum
-thread 'main' panicked at 'explicit panic', $DIR/test-thread-capture.rs:32:5
+thread 'thready_fail' panicked at 'explicit panic', $DIR/test-thread-capture.rs:32:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
-thread 'main' panicked at 'explicit panic', $DIR/test-thread-nocapture.rs:32:5
+thread 'thready_fail' panicked at 'explicit panic', $DIR/test-thread-nocapture.rs:32:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
--- /dev/null
+// compile-flags: -Z track-diagnostics
+// error-pattern: created at
+
+// Normalize the emitted location so this doesn't need
+// updating everytime someone adds or removes a line.
+// normalize-stderr-test ".rs:\d+:\d+" -> ".rs:LL:CC"
+// normalize-stderr-test "note: rustc .+ running on .+" -> "note: rustc $$VERSION running on $$TARGET"
+
+fn main() {
+ break rust
+}
--- /dev/null
+error[E0425]: cannot find value `rust` in this scope
+ --> $DIR/track.rs:LL:CC
+ |
+LL | break rust
+ | ^^^^ not found in this scope
+-Ztrack-diagnostics: created at compiler/rustc_resolve/src/late/diagnostics.rs:LL:CC
+
+error[E0268]: `break` outside of a loop or labeled block
+ --> $DIR/track.rs:LL:CC
+ |
+LL | break rust
+ | ^^^^^^^^^^ cannot `break` outside of a loop or labeled block
+-Ztrack-diagnostics: created at compiler/rustc_passes/src/loops.rs:LL:CC
+
+error: internal compiler error: It looks like you're trying to break rust; would you like some ICE?
+
+note: the compiler expectedly panicked. this is a feature.
+
+note: we would appreciate a joke overview: https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675
+
+note: rustc $VERSION running on $TARGET
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0268, E0425.
+For more information about an error, try `rustc --explain E0268`.
--- /dev/null
+// compile-flags: -Z track-diagnostics
+// error-pattern: created at
+
+// Normalize the emitted location so this doesn't need
+// updating everytime someone adds or removes a line.
+// normalize-stderr-test ".rs:\d+:\d+" -> ".rs:LL:CC"
+
+fn main() {
+ let _moved @ _from = String::from("foo");
+}
--- /dev/null
+error[E0382]: use of moved value
+ --> $DIR/track2.rs:LL:CC
+ |
+LL | let _moved @ _from = String::from("foo");
+ | ^^^^^^ ----- ------------------- move occurs because value has type `String`, which does not implement the `Copy` trait
+ | | |
+ | | value moved here
+ | value used here after move
+-Ztrack-diagnostics: created at compiler/rustc_borrowck/src/borrowck_errors.rs:LL:CC
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0382`.
--- /dev/null
+// compile-flags: -Z track-diagnostics
+// error-pattern: created at
+
+// Normalize the emitted location so this doesn't need
+// updating everytime someone adds or removes a line.
+// normalize-stderr-test ".rs:\d+:\d+" -> ".rs:LL:CC"
+
+fn main() {
+ let _unimported = Blah { field: u8 };
+}
--- /dev/null
+error[E0422]: cannot find struct, variant or union type `Blah` in this scope
+ --> $DIR/track3.rs:LL:CC
+ |
+LL | let _unimported = Blah { field: u8 };
+ | ^^^^ not found in this scope
+-Ztrack-diagnostics: created at compiler/rustc_resolve/src/late/diagnostics.rs:LL:CC
+
+error[E0423]: expected value, found builtin type `u8`
+ --> $DIR/track3.rs:LL:CC
+ |
+LL | let _unimported = Blah { field: u8 };
+ | ^^ not a value
+-Ztrack-diagnostics: created at compiler/rustc_resolve/src/late/diagnostics.rs:LL:CC
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0422, E0423.
+For more information about an error, try `rustc --explain E0422`.
--- /dev/null
+// compile-flags: -Z track-diagnostics
+// error-pattern: created at
+
+// Normalize the emitted location so this doesn't need
+// updating everytime someone adds or removes a line.
+// normalize-stderr-test ".rs:\d+:\d+" -> ".rs:LL:CC"
+
+pub onion {
+ Owo(u8),
+ Uwu(i8),
+}
+
+fn main() {}
--- /dev/null
+error: missing `struct` for struct definition
+ --> $DIR/track4.rs:LL:CC
+ |
+LL | pub onion {
+ | ^
+-Ztrack-diagnostics: created at compiler/rustc_parse/src/parser/diagnostics.rs:LL:CC
+ |
+help: add `struct` here to parse `onion` as a public struct
+ |
+LL | pub struct onion {
+ | ++++++
+
+error: aborting due to previous error
+
--- /dev/null
+// compile-flags: -Z track-diagnostics
+// error-pattern: created at
+
+// Normalize the emitted location so this doesn't need
+// updating everytime someone adds or removes a line.
+// normalize-stderr-test ".rs:\d+:\d+" -> ".rs:LL:CC"
+
+}
--- /dev/null
+error: unexpected closing delimiter: `}`
+ --> $DIR/track5.rs:LL:CC
+ |
+LL | }
+ | ^ unexpected closing delimiter
+-Ztrack-diagnostics: created at compiler/rustc_parse/src/lexer/tokentrees.rs:LL:CC
+
+error: aborting due to previous error
+
--- /dev/null
+// compile-flags: -Z track-diagnostics
+// error-pattern: created at
+
+
+
+pub trait Foo {
+ fn bar();
+}
+
+impl <T> Foo for T {
+ default fn bar() {}
+}
+
+fn main() {}
--- /dev/null
+error[E0658]: specialization is unstable
+ --> $DIR/track6.rs:11:5
+ |
+LL | default fn bar() {}
+ | ^^^^^^^^^^^^^^^^^^^
+-Ztrack-diagnostics: created at $COMPILER_DIR/rustc_session/src/parse.rs:93:5
+ |
+ = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information
+ = help: add `#![feature(specialization)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
| |
| required by a bound introduced by this call
|
- = note: multiple `impl`s satisfying `u32: From<_>` found in the following crates: `core`, `std`:
- - impl From<Ipv4Addr> for u32;
- - impl From<NonZeroU32> for u32;
- - impl From<bool> for u32;
- - impl From<char> for u32;
- and 3 more
+ = note: cannot satisfy `u32: From<_>`
help: try using a fully qualified path to specify the expected types
|
LL | let ips: Vec<_> = (0..100_000).map(|_| u32::from(<u32 as Into<T>>::into(0u32))).collect();
--- /dev/null
+// build-pass
+// compile-flags:-C link-dead-code=y
+
+#![feature(negative_impls)]
+
+trait Foo {
+ fn foo() {}
+}
+
+impl !Foo for () {}
+
+fn main() {}
LL | | }
LL | | }
| |_^
+ |
+ = note: the trait `Foo` enforces invariants that the compiler can't check. Review the trait documentation and make sure this implementation upholds those invariants before adding the `unsafe` keyword
+help: add `unsafe` to this trait implementation
+ |
+LL | unsafe impl lib::Foo for Bar {
+ | ++++++
error: aborting due to previous error
|
LL | impl UnsafeTrait for u16 { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: the trait `UnsafeTrait` enforces invariants that the compiler can't check. Review the trait documentation and make sure this implementation upholds those invariants before adding the `unsafe` keyword
+help: add `unsafe` to this trait implementation
+ |
+LL | unsafe impl UnsafeTrait for u16 { }
+ | ++++++
error[E0199]: implementing the trait `SafeTrait` is not unsafe
--> $DIR/safety-trait-impl.rs:16:1
|
LL | unsafe impl SafeTrait for u32 { }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: remove `unsafe` from this trait implementation
+ |
+LL - unsafe impl SafeTrait for u32 { }
+LL + impl SafeTrait for u32 { }
+ |
error: aborting due to 2 previous errors
--- /dev/null
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
+ pub struct Context;
+
+ pub fn is_maybe_transmutable<Src, Dst>()
+ where
+ Dst: BikeshedIntrinsicFrom<
+ Src,
+ Context,
+ { Assume { alignment: true, lifetimes: true, safety: true, validity: true } },
+ >,
+ {
+ }
+}
+
+fn test() {
+ type NaughtyLenArray = [u32; 3.14159]; //~ ERROR mismatched types
+ type JustUnit = ();
+ assert::is_maybe_transmutable::<JustUnit, NaughtyLenArray>();
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-103783-array-length.rs:21:34
+ |
+LL | type NaughtyLenArray = [u32; 3.14159];
+ | ^^^^^^^ expected `usize`, found floating-point number
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
--- /dev/null
+#![crate_type = "lib"]
+#![feature(transmutability)]
+#![allow(dead_code)]
+
+mod assert {
+ use std::mem::{Assume, BikeshedIntrinsicFrom};
+ pub struct Context;
+
+ pub fn is_maybe_transmutable<Src, Dst>()
+ where
+ Dst: BikeshedIntrinsicFrom<
+ Src,
+ Context,
+ { Assume { alignment: true, lifetimes: true, safety: true, validity: true } },
+ >,
+ {
+ }
+}
+
+fn test() {
+ #[repr(C, align(2))]
+ struct A(u8, u8);
+
+ #[repr(C)]
+ struct B(u8, u8);
+
+ assert::is_maybe_transmutable::<B, A>();
+ //~^ ERROR cannot be safely transmuted
+}
--- /dev/null
+error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`.
+ --> $DIR/transmute-padding-ice.rs:27:40
+ |
+LL | assert::is_maybe_transmutable::<B, A>();
+ | ^ `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`.
+ |
+ = help: the trait `BikeshedIntrinsicFrom<B, assert::Context, Assume { alignment: true, lifetimes: true, safety: true, validity: true }>` is not implemented for `A`
+note: required by a bound in `is_maybe_transmutable`
+ --> $DIR/transmute-padding-ice.rs:11:14
+ |
+LL | pub fn is_maybe_transmutable<Src, Dst>()
+ | --------------------- required by a bound in this
+LL | where
+LL | Dst: BikeshedIntrinsicFrom<
+ | ______________^
+LL | | Src,
+LL | | Context,
+LL | | { Assume { alignment: true, lifetimes: true, safety: true, validity: true } },
+LL | | >,
+ | |_________^ required by this bound in `is_maybe_transmutable`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
note: ...which requires const-evaluating + checking `Alpha::V3::{constant#0}`...
--> $DIR/self-in-enum-definition.rs:5:10
|
+LL | V3 = Self::V1 {} as u8 + 2,
+ | ^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires caching mir of `Alpha::V3::{constant#0}` for CTFE...
+ --> $DIR/self-in-enum-definition.rs:5:10
+ |
+LL | V3 = Self::V1 {} as u8 + 2,
+ | ^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires elaborating drops for `Alpha::V3::{constant#0}`...
+ --> $DIR/self-in-enum-definition.rs:5:10
+ |
+LL | V3 = Self::V1 {} as u8 + 2,
+ | ^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires borrow-checking `Alpha::V3::{constant#0}`...
+ --> $DIR/self-in-enum-definition.rs:5:10
+ |
+LL | V3 = Self::V1 {} as u8 + 2,
+ | ^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires processing MIR for `Alpha::V3::{constant#0}`...
+ --> $DIR/self-in-enum-definition.rs:5:10
+ |
+LL | V3 = Self::V1 {} as u8 + 2,
+ | ^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires const checking `Alpha::V3::{constant#0}`...
+ --> $DIR/self-in-enum-definition.rs:5:10
+ |
+LL | V3 = Self::V1 {} as u8 + 2,
+ | ^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires preparing `Alpha::V3::{constant#0}` for borrow checking...
+ --> $DIR/self-in-enum-definition.rs:5:10
+ |
+LL | V3 = Self::V1 {} as u8 + 2,
+ | ^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires unsafety-checking `Alpha::V3::{constant#0}`...
+ --> $DIR/self-in-enum-definition.rs:5:10
+ |
+LL | V3 = Self::V1 {} as u8 + 2,
+ | ^^^^^^^^^^^^^^^^^^^^^
+note: ...which requires building MIR for `Alpha::V3::{constant#0}`...
+ --> $DIR/self-in-enum-definition.rs:5:10
+ |
LL | V3 = Self::V1 {} as u8 + 2,
| ^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires computing layout of `Alpha`...
--- /dev/null
+#![feature(type_alias_impl_trait)]
+
+// check-pass
+
+trait Trait {}
+
+type TAIT = impl Trait;
+
+struct Concrete;
+impl Trait for Concrete {}
+
+fn tait() -> TAIT {
+ Concrete
+}
+
+trait OuterTrait {
+ type Item;
+}
+struct Dummy<T> {
+ t: T,
+}
+impl<T> OuterTrait for Dummy<T> {
+ type Item = T;
+}
+
+fn tait_and_impl_trait() -> impl OuterTrait<Item = (TAIT, impl Trait)> {
+ Dummy {
+ t: (tait(), Concrete),
+ }
+}
+
+fn tait_and_dyn_trait() -> impl OuterTrait<Item = (TAIT, Box<dyn Trait>)> {
+ let b: Box<dyn Trait> = Box::new(Concrete);
+ Dummy { t: (tait(), b) }
+}
+
+fn main() {}
+// check-pass
// Regression test for issue #57611
// Ensures that we don't ICE
-// FIXME: This should compile, but it currently doesn't
-// known-bug: unknown
#![feature(trait_alias)]
#![feature(type_alias_impl_trait)]
+++ /dev/null
-error[E0308]: mismatched types
- --> $DIR/issue-57611-trait-alias.rs:21:9
- |
-LL | |x| x
- | ^^^^^ one type is more general than the other
- |
- = note: expected trait `for<'a> Fn<(&'a X,)>`
- found trait `Fn<(&X,)>`
-note: this closure does not fulfill the lifetime requirements
- --> $DIR/issue-57611-trait-alias.rs:21:9
- |
-LL | |x| x
- | ^^^
-
-error: implementation of `FnOnce` is not general enough
- --> $DIR/issue-57611-trait-alias.rs:21:9
- |
-LL | |x| x
- | ^^^^^ implementation of `FnOnce` is not general enough
- |
- = note: closure with signature `fn(&'2 X) -> &X` must implement `FnOnce<(&'1 X,)>`, for any lifetime `'1`...
- = note: ...but it actually implements `FnOnce<(&'2 X,)>`, for some specific lifetime `'2`
-
-error: aborting due to 2 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
-// Check to insure that the output of `std::any::type_name` does not change based on -Zverbose
-// when printing constants
+// Check to insure that the output of `std::any::type_name` does not change based on `-Zverbose`
// run-pass
// edition: 2018
// revisions: normal verbose
// [verbose]compile-flags:-Zverbose
-struct Wrapper<const VALUE: usize>;
+use std::any::type_name;
fn main() {
- assert_eq!(std::any::type_name::<[u32; 0]>(), "[u32; 0]");
- assert_eq!(std::any::type_name::<Wrapper<0>>(), "issue_94187_verbose_type_name::Wrapper<0>");
+ assert_eq!(type_name::<[u32; 0]>(), "[u32; 0]");
+
+ struct Wrapper<const VALUE: usize>;
+ assert_eq!(type_name::<Wrapper<0>>(), "issue_94187_verbose_type_name::main::Wrapper<0>");
+
+ assert_eq!(type_name::<dyn Fn(u32) -> u32>(), "dyn core::ops::function::Fn(u32) -> u32");
}
--- /dev/null
+fn func(i: i32) {
+ i(); //~ERROR expected function, found `i32`
+}
+fn main() {
+ let i = 0i32;
+ i(); //~ERROR expected function, found `i32`
+}
--- /dev/null
+error[E0618]: expected function, found `i32`
+ --> $DIR/issue-10969.rs:2:5
+ |
+LL | fn func(i: i32) {
+ | - `i` has type `i32`
+LL | i();
+ | ^--
+ | |
+ | call expression requires function
+
+error[E0618]: expected function, found `i32`
+ --> $DIR/issue-10969.rs:6:5
+ |
+LL | let i = 0i32;
+ | - `i` has type `i32`
+LL | i();
+ | ^--
+ | |
+ | call expression requires function
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0618`.
--- /dev/null
+// This previously caused an ICE at:
+// librustc/traits/structural_impls.rs:180: impossible case reached
+
+#![no_main]
+
+use std::borrow::Borrow;
+use std::io;
+use std::io::Write;
+
+trait Constraint {}
+
+struct Container<T> {
+ t: T,
+}
+
+struct Borrowed;
+struct Owned;
+
+impl<'a, T> Write for &'a Container<T>
+where
+ T: Constraint,
+ &'a T: Write,
+{
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ Ok(buf.len())
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+impl Borrow<Borrowed> for Owned {
+ fn borrow(&self) -> &Borrowed {
+ &Borrowed
+ }
+}
+
+fn func(owned: Owned) {
+ let _: () = Borrow::borrow(&owned); //~ ERROR mismatched types
+}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/issue-50687-ice-on-borrow.rs:40:17
+ |
+LL | let _: () = Borrow::borrow(&owned);
+ | -- ^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found reference
+ | |
+ | expected due to this
+ |
+ = note: expected unit type `()`
+ found reference `&_`
+help: consider dereferencing the borrow
+ |
+LL | let _: () = *Borrow::borrow(&owned);
+ | +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
|
::: $SRC_DIR/core/src/ops/function.rs:LL:COL
|
-LL | pub trait Fn<Args>: FnMut<Args> {
- | ------------------------------- similarly named trait `Fn` defined here
+LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
+ | -------------------------------------- similarly named trait `Fn` defined here
error[E0412]: cannot find type `TestResult` in this scope
--> $DIR/issue-83693.rs:9:22
+++ /dev/null
-// compile-flags: -Z ui-testing=no
-
-// Line number < 10
-type A = B; //~ ERROR
-
-// Line number >=10, <100
-type C = D; //~ ERROR
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-// Line num >=100
-type E = F; //~ ERROR
-
-fn main() {}
+++ /dev/null
-error[E0412]: cannot find type `B` in this scope
- --> $DIR/ui-testing-optout.rs:4:10
- |
-4 | type A = B;
- | ^ not found in this scope
-
-error[E0412]: cannot find type `D` in this scope
- --> $DIR/ui-testing-optout.rs:7:10
- |
-4 | type A = B;
- | ----------- similarly named type alias `A` defined here
-...
-7 | type C = D;
- | ^ help: a type alias with a similar name exists: `A`
-
-error[E0412]: cannot find type `F` in this scope
- --> $DIR/ui-testing-optout.rs:92:10
- |
-4 | type A = B;
- | ----------- similarly named type alias `A` defined here
-...
-92 | type E = F;
- | ^ help: a type alias with a similar name exists: `A`
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0412`.
#![feature(unboxed_closures)]
fn a<F: Fn<usize>>(f: F) {}
+//~^ ERROR type parameter to bare `Fn` trait must be a tuple
fn main() {
a(|_: usize| {});
- //~^ ERROR mismatched types
}
-error[E0308]: mismatched types
- --> $DIR/non-tupled-arg-mismatch.rs:6:5
- |
-LL | a(|_: usize| {});
- | ^ types differ
- |
- = note: expected trait `Fn<usize>`
- found trait `Fn<(usize,)>`
-note: required by a bound in `a`
+error[E0059]: type parameter to bare `Fn` trait must be a tuple
--> $DIR/non-tupled-arg-mismatch.rs:3:9
|
LL | fn a<F: Fn<usize>>(f: F) {}
- | ^^^^^^^^^ required by this bound in `a`
+ | ^^^^^^^^^ the trait `Tuple` is not implemented for `usize`
+ |
+note: required by a bound in `Fn`
+ --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+ |
+LL | pub trait Fn<Args: Tuple>: FnMut<Args> {
+ | ^^^^^ required by this bound in `Fn`
error: aborting due to previous error
-For more information about this error, try `rustc --explain E0308`.
+For more information about this error, try `rustc --explain E0059`.
-#![feature(unboxed_closures)]
+#![feature(unboxed_closures, tuple_trait)]
// Tests that we can't move out of an unboxed closure environment
// if the upvar is captured by ref or the closure takes self by
// reference.
-fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
-fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
-fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
+fn to_fn<A:std::marker::Tuple,F:Fn<A>>(f: F) -> F { f }
+fn to_fn_mut<A:std::marker::Tuple,F:FnMut<A>>(f: F) -> F { f }
+fn to_fn_once<A:std::marker::Tuple,F:FnOnce<A>>(f: F) -> F { f }
fn main() {
// By-ref cases
// as `mut` through a closure. Also test that we CAN mutate a moved copy,
// unless this is a `Fn` closure. Issue #16749.
-#![feature(unboxed_closures)]
+#![feature(unboxed_closures, tuple_trait)]
use std::mem;
-fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
-fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
+fn to_fn<A:std::marker::Tuple,F:Fn<A>>(f: F) -> F { f }
+fn to_fn_mut<A:std::marker::Tuple,F:FnMut<A>>(f: F) -> F { f }
fn a() {
let n = 0;
error[E0594]: cannot assign to `n`, as it is a captured variable in a `Fn` closure
--> $DIR/unboxed-closures-mutate-upvar.rs:53:9
|
-LL | fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
- | - change this to accept `FnMut` instead of `Fn`
+LL | fn to_fn<A:std::marker::Tuple,F:Fn<A>>(f: F) -> F { f }
+ | - change this to accept `FnMut` instead of `Fn`
...
LL | let mut f = to_fn(move || {
| ----- ------- in this closure
-#![feature(unboxed_closures)]
+#![feature(unboxed_closures, tuple_trait)]
-fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
+fn to_fn_mut<A:std::marker::Tuple,F:FnMut<A>>(f: F) -> F { f }
fn main() {
let mut_ = to_fn_mut(|x| x);
--- /dev/null
+#![allow(unused, dead_code)]
+
+static mut FOO: u64 = 0;
+
+fn static_mod() {
+ unsafe {static BAR: u64 = FOO;}
+ //~^ ERROR: use of mutable static is unsafe
+ //~| NOTE: use of mutable static
+ //~| NOTE: mutable statics can be mutated by multiple threads
+ //~| NOTE: items do not inherit unsafety
+}
+
+unsafe fn unsafe_call() {}
+fn foo() {
+ unsafe {
+ //~^ NOTE: items do not inherit unsafety
+ fn bar() {
+ unsafe_call();
+ //~^ ERROR: call to unsafe function
+ //~| NOTE: call to unsafe function
+ //~| NOTE: consult the function's documentation
+ }
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0133]: use of mutable static is unsafe and requires unsafe function or block
+ --> $DIR/unsafe-not-inherited.rs:6:31
+ |
+LL | unsafe {static BAR: u64 = FOO;}
+ | ------ ^^^ use of mutable static
+ | |
+ | items do not inherit unsafety from separate enclosing items
+ |
+ = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+
+error[E0133]: call to unsafe function is unsafe and requires unsafe function or block
+ --> $DIR/unsafe-not-inherited.rs:18:13
+ |
+LL | unsafe {
+ | ------ items do not inherit unsafety from separate enclosing items
+...
+LL | unsafe_call();
+ | ^^^^^^^^^^^^^ call to unsafe function
+ |
+ = note: consult the function's documentation for information on how to avoid undefined behavior
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0133`.
#![allow(unreachable_code)]
#![allow(unused_braces, unused_must_use, unused_parens)]
#![allow(uncommon_codepoints, confusable_idents)]
+#![allow(unreachable_patterns)]
#![recursion_limit = "256"]
assert_eq!(i, 13);
}
+fn closure_matching() {
+ let x = |_| Some(1);
+ let (|x| x) = match x(..) {
+ |_| Some(2) => |_| Some(3),
+ |_| _ => unreachable!(),
+ };
+ assert!(matches!(x(..), |_| Some(4)));
+}
+
pub fn main() {
strange();
funny();
𝚌𝚘𝚗𝚝𝚒𝚗𝚞𝚎();
function();
bathroom_stall();
+ closure_matching();
}
--- /dev/null
+trait TraitA {
+ type TypeA;
+}
+
+trait TraitD {
+ type TypeD;
+}
+
+pub trait TraitB {
+ type TypeB: TraitD;
+
+ fn f(_: &<Self::TypeB as TraitD>::TypeD);
+}
+
+pub trait TraitC<E> {
+ type TypeC<'a>: TraitB;
+
+ fn g<'a>(_: &<<Self::TypeC<'a> as TraitB>::TypeB as TraitA>::TypeA);
+ //~^ ERROR the trait bound `<<Self as TraitC<E>>::TypeC<'a> as TraitB>::TypeB: TraitA` is not satisfied
+}
+
+fn main() {}
--- /dev/null
+error[E0277]: the trait bound `<<Self as TraitC<E>>::TypeC<'a> as TraitB>::TypeB: TraitA` is not satisfied
+ --> $DIR/issue-103573.rs:18:5
+ |
+LL | fn g<'a>(_: &<<Self::TypeC<'a> as TraitB>::TypeB as TraitA>::TypeA);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TraitA` is not implemented for `<<Self as TraitC<E>>::TypeC<'a> as TraitB>::TypeB`
+ |
+help: consider further restricting the associated type
+ |
+LL | fn g<'a>(_: &<<Self::TypeC<'a> as TraitB>::TypeB as TraitA>::TypeA) where <<Self as TraitC<E>>::TypeC<'a> as TraitB>::TypeB: TraitA;
+ | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
# build-manifest
-This tool generates the manifests uploaded to static.rust-lang.org and used by
-rustup. The tool is invoked by the bootstrap tool.
+This tool generates the manifests uploaded to static.rust-lang.org and used by rustup.
+You can see a full list of all manifests at <https://static.rust-lang.org/manifests.txt>.
+This listing is updated by <https://github.com/rust-lang/generate-manifest-list> every 7 days.
+
+This gets called by `promote-release` <https://github.com/rust-lang/promote-release> via `x.py dist hash-and-sign`.
+
+## Adding a new component
+
+1. Add a new `Step` to `dist.rs`. This should usually be named after the filename of the uploaded tarball. See https://github.com/rust-lang/rust/pull/101799/files#diff-2c56335faa24486df09ba392d8900c57e2fac4633e1f7038469bcf9ed3feb871 for an example.
+ a. If appropriate, call `tarball.is_preview(true)` for the component.
+2. Add a new `PkgType` to build-manifest. Fix all the compile errors as appropriate.
## Testing changes locally
available locally. If you don't want to build all the compiler, you can easily
create one from the nightly artifacts with:
-```
-#!/bin/bash
-for cmpn in rust rustc rust-std rust-docs cargo; do
- wget https://static.rust-lang.org/dist/${cmpn}-nightly-x86_64-unknown-linux-gnu.tar.gz
+```sh
+for component in rust rustc rust-std rust-docs cargo; do
+ wget -P build/dist https://static.rust-lang.org/dist/${component}-nightly-x86_64-unknown-linux-gnu.tar.gz
done
```
-Then, you can generate the manifest and all the packages from `path/to/dist` to
-`path/to/output` with:
+Then, you can generate the manifest and all the packages from `build/dist` to
+`build/manifest` with:
+```sh
+mkdir -p build/manifest
+cargo +nightly run --release -p build-manifest build/dist build/manifest 1970-01-01 http://example.com nightly
```
-$ cargo +nightly run path/to/dist path/to/output 1970-01-01 http://example.com CHANNEL
-```
-
-Remember to replace `CHANNEL` with the channel you produced dist artifacts of
-and `VERSION` with the current Rust version.
-//! Build a dist manifest, hash and sign everything.
-//! This gets called by `promote-release`
-//! (https://github.com/rust-lang/rust-central-station/tree/master/promote-release)
-//! via `x.py dist hash-and-sign`; the cmdline arguments are set up
-//! by rustbuild (in `src/bootstrap/dist.rs`).
+#![doc = include_str!("../README.md")]
mod checksum;
mod manifest;
static MINGW: &[&str] = &["i686-pc-windows-gnu", "x86_64-pc-windows-gnu"];
-static NIGHTLY_ONLY_COMPONENTS: &[&str] = &["miri-preview", "rust-docs-json-preview"];
+static NIGHTLY_ONLY_COMPONENTS: &[PkgType] = &[PkgType::Miri, PkgType::JsonDocs];
macro_rules! t {
($e:expr) => {
}
fn add_packages_to(&mut self, manifest: &mut Manifest) {
- macro_rules! package {
- ($name:expr, $targets:expr) => {
- self.package($name, &mut manifest.pkg, $targets, &[])
- };
+ for pkg in PkgType::all() {
+ self.package(pkg, &mut manifest.pkg);
}
- package!("rustc", HOSTS);
- package!("rustc-dev", HOSTS);
- package!("reproducible-artifacts", HOSTS);
- package!("rustc-docs", HOSTS);
- package!("cargo", HOSTS);
- package!("rust-mingw", MINGW);
- package!("rust-std", TARGETS);
- self.package("rust-docs", &mut manifest.pkg, HOSTS, DOCS_FALLBACK);
- self.package("rust-docs-json-preview", &mut manifest.pkg, HOSTS, DOCS_FALLBACK);
- package!("rust-src", &["*"]);
- package!("rls-preview", HOSTS);
- package!("rust-analyzer-preview", HOSTS);
- package!("clippy-preview", HOSTS);
- package!("miri-preview", HOSTS);
- package!("rustfmt-preview", HOSTS);
- package!("rust-analysis", TARGETS);
- package!("llvm-tools-preview", TARGETS);
}
fn add_artifacts_to(&mut self, manifest: &mut Manifest) {
}
fn add_profiles_to(&mut self, manifest: &mut Manifest) {
- let mut profile = |name, pkgs| self.profile(name, &mut manifest.profiles, pkgs);
- profile("minimal", &["rustc", "cargo", "rust-std", "rust-mingw"]);
- profile(
- "default",
- &[
- "rustc",
- "cargo",
- "rust-std",
- "rust-mingw",
- "rust-docs",
- "rustfmt-preview",
- "clippy-preview",
- ],
- );
- profile(
- "complete",
- &[
- "rustc",
- "cargo",
- "rust-std",
- "rust-mingw",
- "rust-docs",
- "rustfmt-preview",
- "clippy-preview",
- "rls-preview",
- "rust-analyzer-preview",
- "rust-src",
- "llvm-tools-preview",
- "rust-analysis",
- "miri-preview",
- ],
- );
+ use PkgType::*;
+
+ let mut profile = |name, pkgs: &_| self.profile(name, &mut manifest.profiles, pkgs);
+
+ // Use a Vec here to make sure we don't exclude any components in an earlier profile.
+ let minimal = vec![Rustc, Cargo, RustStd, RustMingw];
+ profile("minimal", &minimal);
+
+ let mut default = minimal;
+ default.extend([HtmlDocs, Rustfmt, Clippy]);
+ profile("default", &default);
+
+ // NOTE: this profile is effectively deprecated; do not add new components to it.
+ let mut complete = default;
+ complete.extend([Rls, RustAnalyzer, RustSrc, LlvmTools, RustAnalysis, Miri]);
+ profile("complete", &complete);
// The compiler libraries are not stable for end users, and they're also huge, so we only
// `rustc-dev` for nightly users, and only in the "complete" profile. It's still possible
// for users to install the additional component manually, if needed.
if self.versions.channel() == "nightly" {
- self.extend_profile("complete", &mut manifest.profiles, &["rustc-dev"]);
+ self.extend_profile("complete", &mut manifest.profiles, &[RustcDev]);
// Do not include the rustc-docs component for now, as it causes
// conflicts with the rust-docs component when installed. See
// #75833.
let mut rename = |from: &str, to: &str| {
manifest.renames.insert(from.to_owned(), Rename { to: to.to_owned() })
};
- rename("rls", "rls-preview");
- rename("rustfmt", "rustfmt-preview");
- rename("clippy", "clippy-preview");
- rename("miri", "miri-preview");
- rename("rust-docs-json", "rust-docs-json-preview");
- rename("rust-analyzer", "rust-analyzer-preview");
+ for pkg in PkgType::all() {
+ if pkg.is_preview() {
+ rename(pkg.tarball_component_name(), &pkg.manifest_component_name());
+ }
+ }
}
fn rust_package(&mut self, manifest: &Manifest) -> Package {
let mut components = Vec::new();
let mut extensions = Vec::new();
- let host_component = |pkg| Component::from_str(pkg, host);
-
- // rustc/rust-std/cargo/docs are all required,
- // and so is rust-mingw if it's available for the target.
- components.extend(vec![
- host_component("rustc"),
- host_component("rust-std"),
- host_component("cargo"),
- host_component("rust-docs"),
- ]);
- if host.contains("pc-windows-gnu") {
- components.push(host_component("rust-mingw"));
- }
+ let host_component = |pkg: &_| Component::from_pkg(pkg, host);
- // Tools are always present in the manifest,
- // but might be marked as unavailable if they weren't built.
- extensions.extend(vec![
- host_component("clippy-preview"),
- host_component("miri-preview"),
- host_component("rls-preview"),
- host_component("rust-analyzer-preview"),
- host_component("rustfmt-preview"),
- host_component("llvm-tools-preview"),
- host_component("rust-analysis"),
- host_component("rust-docs-json-preview"),
- ]);
-
- extensions.extend(
- TARGETS
- .iter()
- .filter(|&&target| target != host)
- .map(|target| Component::from_str("rust-std", target)),
- );
- extensions.extend(HOSTS.iter().map(|target| Component::from_str("rustc-dev", target)));
- extensions.extend(HOSTS.iter().map(|target| Component::from_str("rustc-docs", target)));
- extensions.push(Component::from_str("rust-src", "*"));
+ for pkg in PkgType::all() {
+ match pkg {
+ // rustc/rust-std/cargo/docs are all required
+ PkgType::Rustc | PkgType::Cargo | PkgType::HtmlDocs => {
+ components.push(host_component(pkg));
+ }
+ PkgType::RustStd => {
+ components.push(host_component(pkg));
+ extensions.extend(
+ TARGETS
+ .iter()
+ .filter(|&&target| target != host)
+ .map(|target| Component::from_pkg(pkg, target)),
+ );
+ }
+ // so is rust-mingw if it's available for the target
+ PkgType::RustMingw => {
+ if host.contains("pc-windows-gnu") {
+ components.push(host_component(pkg));
+ }
+ }
+ // Tools are always present in the manifest,
+ // but might be marked as unavailable if they weren't built.
+ PkgType::Clippy
+ | PkgType::Miri
+ | PkgType::Rls
+ | PkgType::RustAnalyzer
+ | PkgType::Rustfmt
+ | PkgType::LlvmTools
+ | PkgType::RustAnalysis
+ | PkgType::JsonDocs => {
+ extensions.push(host_component(pkg));
+ }
+ PkgType::RustcDev | PkgType::RustcDocs => {
+ extensions.extend(HOSTS.iter().map(|target| Component::from_pkg(pkg, target)));
+ }
+ PkgType::RustSrc => {
+ extensions.push(Component::from_pkg(pkg, "*"));
+ }
+ PkgType::Rust => {}
+ // NOTE: this is intentional, these artifacts aren't intended to be used with rustup
+ PkgType::ReproducibleArtifacts => {}
+ }
+ }
// If the components/extensions don't actually exist for this
// particular host/target combination then nix it entirely from our
&mut self,
profile_name: &str,
dst: &mut BTreeMap<String, Vec<String>>,
- pkgs: &[&str],
+ pkgs: &[PkgType],
) {
- dst.insert(profile_name.to_owned(), pkgs.iter().map(|s| (*s).to_owned()).collect());
+ dst.insert(
+ profile_name.to_owned(),
+ pkgs.iter().map(|s| s.manifest_component_name()).collect(),
+ );
}
fn extend_profile(
&mut self,
profile_name: &str,
dst: &mut BTreeMap<String, Vec<String>>,
- pkgs: &[&str],
+ pkgs: &[PkgType],
) {
dst.get_mut(profile_name)
.expect("existing profile")
- .extend(pkgs.iter().map(|s| (*s).to_owned()));
+ .extend(pkgs.iter().map(|s| s.manifest_component_name()));
}
- fn package(
- &mut self,
- pkgname: &str,
- dst: &mut BTreeMap<String, Package>,
- targets: &[&str],
- fallback: &[(&str, &str)],
- ) {
- let version_info = self
- .versions
- .version(&PkgType::from_component(pkgname))
- .expect("failed to load package version");
+ fn package(&mut self, pkg: &PkgType, dst: &mut BTreeMap<String, Package>) {
+ if *pkg == PkgType::Rust {
+ // This is handled specially by `rust_package` later.
+ // Order is important, so don't call `rust_package` here.
+ return;
+ }
+
+ let fallback = if pkg.use_docs_fallback() { DOCS_FALLBACK } else { &[] };
+ let version_info = self.versions.version(&pkg).expect("failed to load package version");
let mut is_present = version_info.present;
// Never ship nightly-only components for other trains.
- if self.versions.channel() != "nightly" && NIGHTLY_ONLY_COMPONENTS.contains(&pkgname) {
+ if self.versions.channel() != "nightly" && NIGHTLY_ONLY_COMPONENTS.contains(&pkg) {
is_present = false; // Pretend the component is entirely missing.
}
macro_rules! tarball_name {
($target_name:expr) => {
- self.versions.tarball_name(&PkgType::from_component(pkgname), $target_name).unwrap()
+ self.versions.tarball_name(pkg, $target_name).unwrap()
};
}
let mut target_from_compressed_tar = |target_name| {
Target::unavailable()
};
- let targets = targets
+ let targets = pkg
+ .targets()
.iter()
.map(|name| {
let target = if is_present {
.collect();
dst.insert(
- pkgname.to_string(),
+ pkg.manifest_component_name(),
Package {
version: version_info.version.unwrap_or_default(),
git_commit_hash: version_info.git_commit,
+use crate::versions::PkgType;
use crate::Builder;
use serde::{Serialize, Serializer};
use std::collections::BTreeMap;
}
impl Component {
- pub(crate) fn from_str(pkg: &str, target: &str) -> Self {
- Self { pkg: pkg.to_string(), target: target.to_string() }
+ pub(crate) fn from_pkg(pkg: &PkgType, target: &str) -> Self {
+ Self { pkg: pkg.manifest_component_name(), target: target.to_string() }
}
}
const DEFAULT_TARGET: &str = "x86_64-unknown-linux-gnu";
-#[derive(Debug, Hash, Eq, PartialEq, Clone)]
-pub(crate) enum PkgType {
- Rust,
- RustSrc,
- Rustc,
- Cargo,
- Rls,
- RustAnalyzer,
- Clippy,
- Rustfmt,
- LlvmTools,
- Miri,
- JsonDocs,
- Other(String),
-}
+macro_rules! pkg_type {
+ ( $($variant:ident = $component:literal $(; preview = true $(@$is_preview:tt)? )? ),+ $(,)? ) => {
+ #[derive(Debug, Hash, Eq, PartialEq, Clone)]
+ pub(crate) enum PkgType {
+ $($variant,)+
+ }
-impl PkgType {
- pub(crate) fn from_component(component: &str) -> Self {
- match component {
- "rust" => PkgType::Rust,
- "rust-src" => PkgType::RustSrc,
- "rustc" => PkgType::Rustc,
- "cargo" => PkgType::Cargo,
- "rls" | "rls-preview" => PkgType::Rls,
- "rust-analyzer" | "rust-analyzer-preview" => PkgType::RustAnalyzer,
- "clippy" | "clippy-preview" => PkgType::Clippy,
- "rustfmt" | "rustfmt-preview" => PkgType::Rustfmt,
- "llvm-tools" | "llvm-tools-preview" => PkgType::LlvmTools,
- "miri" | "miri-preview" => PkgType::Miri,
- "rust-docs-json" | "rust-docs-json-preview" => PkgType::JsonDocs,
- other => PkgType::Other(other.into()),
+ impl PkgType {
+ pub(crate) fn is_preview(&self) -> bool {
+ match self {
+ $( $( $($is_preview)? PkgType::$variant => true, )? )+
+ _ => false,
+ }
+ }
+
+ /// First part of the tarball name.
+ pub(crate) fn tarball_component_name(&self) -> &str {
+ match self {
+ $( PkgType::$variant => $component,)+
+ }
+ }
+
+ pub(crate) fn all() -> &'static [PkgType] {
+ &[ $(PkgType::$variant),+ ]
+ }
}
}
+}
- /// First part of the tarball name.
- fn tarball_component_name(&self) -> &str {
- match self {
- PkgType::Rust => "rust",
- PkgType::RustSrc => "rust-src",
- PkgType::Rustc => "rustc",
- PkgType::Cargo => "cargo",
- PkgType::Rls => "rls",
- PkgType::RustAnalyzer => "rust-analyzer",
- PkgType::Clippy => "clippy",
- PkgType::Rustfmt => "rustfmt",
- PkgType::LlvmTools => "llvm-tools",
- PkgType::Miri => "miri",
- PkgType::JsonDocs => "rust-docs-json",
- PkgType::Other(component) => component,
+pkg_type! {
+ Rust = "rust",
+ RustSrc = "rust-src",
+ Rustc = "rustc",
+ RustcDev = "rustc-dev",
+ RustcDocs = "rustc-docs",
+ ReproducibleArtifacts = "reproducible-artifacts",
+ RustMingw = "rust-mingw",
+ RustStd = "rust-std",
+ Cargo = "cargo",
+ HtmlDocs = "rust-docs",
+ RustAnalysis = "rust-analysis",
+ Rls = "rls"; preview = true,
+ RustAnalyzer = "rust-analyzer"; preview = true,
+ Clippy = "clippy"; preview = true,
+ Rustfmt = "rustfmt"; preview = true,
+ LlvmTools = "llvm-tools"; preview = true,
+ Miri = "miri"; preview = true,
+ JsonDocs = "rust-docs-json"; preview = true,
+}
+
+impl PkgType {
+ /// Component name in the manifest. In particular, this includes the `-preview` suffix where appropriate.
+ pub(crate) fn manifest_component_name(&self) -> String {
+ if self.is_preview() {
+ format!("{}-preview", self.tarball_component_name())
+ } else {
+ self.tarball_component_name().to_string()
}
}
PkgType::Miri => false,
PkgType::Rust => true,
+ PkgType::RustStd => true,
PkgType::RustSrc => true,
PkgType::Rustc => true,
PkgType::JsonDocs => true,
- PkgType::Other(_) => true,
+ PkgType::HtmlDocs => true,
+ PkgType::RustcDev => true,
+ PkgType::RustcDocs => true,
+ PkgType::ReproducibleArtifacts => true,
+ PkgType::RustMingw => true,
+ PkgType::RustAnalysis => true,
+ }
+ }
+
+ pub(crate) fn targets(&self) -> &[&str] {
+ use crate::{HOSTS, MINGW, TARGETS};
+ use PkgType::*;
+
+ match self {
+ Rust => HOSTS, // doesn't matter in practice, but return something to avoid panicking
+ Rustc => HOSTS,
+ RustcDev => HOSTS,
+ ReproducibleArtifacts => HOSTS,
+ RustcDocs => HOSTS,
+ Cargo => HOSTS,
+ RustMingw => MINGW,
+ RustStd => TARGETS,
+ HtmlDocs => HOSTS,
+ JsonDocs => HOSTS,
+ RustSrc => &["*"],
+ Rls => HOSTS,
+ RustAnalyzer => HOSTS,
+ Clippy => HOSTS,
+ Miri => HOSTS,
+ Rustfmt => HOSTS,
+ RustAnalysis => TARGETS,
+ LlvmTools => TARGETS,
}
}
fn target_independent(&self) -> bool {
*self == PkgType::RustSrc
}
+
+ /// Whether to package these target-specific docs for another similar target.
+ pub(crate) fn use_docs_fallback(&self) -> bool {
+ match self {
+ PkgType::JsonDocs | PkgType::HtmlDocs => true,
+ _ => false,
+ }
+ }
}
#[derive(Debug, Default, Clone)]
-Subproject commit 9210810d1fd7b51ae0439a0a363cc50e36963455
+Subproject commit 9286a1beba5b28b115bad67de2ae91fb1c61eb0b
(Mutability::Not, Mutability::Not) | (Mutability::Mut, Mutability::Mut));
// The `U` in `pointer::cast` have to be `Sized`
// as explained here: https://github.com/rust-lang/rust/issues/60602.
- if to_pointee_ty.is_sized(cx.tcx.at(expr.span), cx.param_env);
+ if to_pointee_ty.is_sized(cx.tcx, cx.param_env);
then {
let mut applicability = Applicability::MachineApplicable;
let cast_expr_sugg = Sugg::hir_with_applicability(cx, cast_expr, "_", &mut applicability);
of_trait: Some(ref trait_ref),
..
}) = item.kind;
- let ty = cx.tcx.type_of(item.def_id);
+ let ty = cx.tcx.type_of(item.owner_id);
if is_copy(cx, ty);
if let Some(trait_id) = trait_ref.trait_def_id();
if cx.tcx.is_diagnostic_item(sym::Iterator, trait_id);
None,
&format!(
"consider annotating `{}` with `#[repr(C)]` to explicitly specify memory layout",
- cx.tcx.def_path_str(item.def_id.to_def_id())
+ cx.tcx.def_path_str(item.owner_id.to_def_id())
),
);
}
};
use rustc_semver::RustcVersion;
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
+use rustc_span::{symbol::sym, Span, Symbol};
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
use std::collections::VecDeque;
},
Node::Item(&Item {
kind: ItemKind::Static(..) | ItemKind::Const(..),
- def_id,
+ owner_id,
span,
..
})
| Node::TraitItem(&TraitItem {
kind: TraitItemKind::Const(..),
- def_id,
+ owner_id,
span,
..
})
| Node::ImplItem(&ImplItem {
kind: ImplItemKind::Const(..),
- def_id,
+ owner_id,
span,
..
}) if span.ctxt() == ctxt => {
- let ty = cx.tcx.type_of(def_id.def_id);
+ let ty = cx.tcx.type_of(owner_id.def_id);
Some(ty_auto_deref_stability(cx, ty, precedence).position_for_result(cx))
},
Node::Item(&Item {
kind: ItemKind::Fn(..),
- def_id,
+ owner_id,
span,
..
})
| Node::TraitItem(&TraitItem {
kind: TraitItemKind::Fn(..),
- def_id,
+ owner_id,
span,
..
})
| Node::ImplItem(&ImplItem {
kind: ImplItemKind::Fn(..),
- def_id,
+ owner_id,
span,
..
}) if span.ctxt() == ctxt => {
let output = cx
.tcx
- .erase_late_bound_regions(cx.tcx.fn_sig(def_id.to_def_id()).output());
+ .erase_late_bound_regions(cx.tcx.fn_sig(owner_id.to_def_id()).output());
Some(ty_auto_deref_stability(cx, output, precedence).position_for_result(cx))
},
cx.typeck_results().node_type(ty.ty.hir_id),
binder_args,
))
- .is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()),
+ .is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
)
}
},
cx.typeck_results().node_type(ty.ty.hir_id),
binder_args,
))
- .is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()),
+ .is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
),
TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err => {
Position::ReborrowStable(precedence)
fn position_for_result(self, cx: &LateContext<'tcx>) -> Position {
match (self.position, self.ty) {
(Position::ReborrowStable(precedence), Some(ty)) => {
- Position::DerefStable(precedence, ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env))
+ Position::DerefStable(precedence, ty.is_sized(cx.tcx, cx.param_env))
},
(position, _) => position,
}
| ty::Tuple(_)
| ty::Projection(_) => Position::DerefStable(
precedence,
- ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()),
+ ty.is_sized(cx.tcx, cx.param_env.without_caller_bounds()),
)
.into(),
};
self_ty,
..
}) = item.kind;
- if !cx.tcx.has_attr(item.def_id.to_def_id(), sym::automatically_derived);
+ if !cx.tcx.has_attr(item.owner_id.to_def_id(), sym::automatically_derived);
if !item.span.from_expansion();
if let Some(def_id) = trait_ref.trait_def_id();
if cx.tcx.is_diagnostic_item(sym::Default, def_id);
if let Some(Node::ImplItem(impl_item)) = cx.tcx.hir().find(impl_item_hir);
if let ImplItemKind::Fn(_, b) = &impl_item.kind;
if let Body { value: func_expr, .. } = cx.tcx.hir().body(*b);
- if let Some(adt_def) = cx.tcx.type_of(item.def_id).ty_adt_def();
+ if let Some(adt_def) = cx.tcx.type_of(item.owner_id).ty_adt_def();
if let attrs = cx.tcx.hir().attrs(item.hir_id());
if !attrs.iter().any(|attr| attr.doc_str().is_some());
if let child_attrs = cx.tcx.hir().attrs(impl_item_hir);
..
}) = item.kind
{
- let ty = cx.tcx.type_of(item.def_id);
- let is_automatically_derived = cx.tcx.has_attr(item.def_id.to_def_id(), sym::automatically_derived);
+ let ty = cx.tcx.type_of(item.owner_id);
+ let is_automatically_derived = cx.tcx.has_attr(item.owner_id.to_def_id(), sym::automatically_derived);
check_hash_peq(cx, item.span, trait_ref, ty, is_automatically_derived);
check_ord_partial_ord(cx, item.span, trait_ref, ty, is_automatically_derived);
let headers = check_attrs(cx, &self.valid_idents, attrs);
match item.kind {
hir::ItemKind::Fn(ref sig, _, body_id) => {
- if !(is_entrypoint_fn(cx, item.def_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) {
+ if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) {
let body = cx.tcx.hir().body(body_id);
let mut fpu = FindPanicUnwrap {
cx,
- typeck_results: cx.tcx.typeck(item.def_id.def_id),
+ typeck_results: cx.tcx.typeck(item.owner_id.def_id),
panic_span: None,
};
fpu.visit_expr(body.value);
lint_for_missing_headers(
cx,
- item.def_id.def_id,
+ item.owner_id.def_id,
item.span,
sig,
headers,
let headers = check_attrs(cx, &self.valid_idents, attrs);
if let hir::TraitItemKind::Fn(ref sig, ..) = item.kind {
if !in_external_macro(cx.tcx.sess, item.span) {
- lint_for_missing_headers(cx, item.def_id.def_id, item.span, sig, headers, None, None);
+ lint_for_missing_headers(cx, item.owner_id.def_id, item.span, sig, headers, None, None);
}
}
}
let body = cx.tcx.hir().body(body_id);
let mut fpu = FindPanicUnwrap {
cx,
- typeck_results: cx.tcx.typeck(item.def_id.def_id),
+ typeck_results: cx.tcx.typeck(item.owner_id.def_id),
panic_span: None,
};
fpu.visit_expr(body.value);
lint_for_missing_headers(
cx,
- item.def_id.def_id,
+ item.owner_id.def_id,
item.span,
sig,
headers,
body_id: Option<hir::BodyId>,
panic_span: Option<Span>,
) {
- if !cx.access_levels.is_exported(def_id) {
+ if !cx.effective_visibilities.is_exported(def_id) {
return; // Private functions do not require doc comments
}
false,
None,
false,
+ false,
);
let handler = Handler::with_emitter(false, None, Box::new(emitter));
let sess = ParseSess::with_span_handler(handler, sm);
}
if let ItemKind::Enum(..) = item.kind {
- let ty = cx.tcx.type_of(item.def_id);
+ let ty = cx.tcx.type_of(item.owner_id);
let adt = ty.ty_adt_def().expect("already checked whether this is an enum");
if adt.variants().is_empty() {
span_lint_and_help(
}
// The `module_name_repetitions` lint should only trigger if the item has the module in its
// name. Having the same name is accepted.
- if cx.tcx.visibility(item.def_id).is_public() && item_camel.len() > mod_camel.len() {
+ if cx.tcx.visibility(item.owner_id).is_public() && item_camel.len() > mod_camel.len() {
let matching = count_match_start(mod_camel, &item_camel);
let rmatching = count_match_end(mod_camel, &item_camel);
let nchars = mod_camel.chars().count();
}
}
if let ItemKind::Enum(ref def, _) = item.kind {
- if !(self.avoid_breaking_exported_api && cx.access_levels.is_exported(item.def_id.def_id)) {
+ if !(self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(item.owner_id.def_id)) {
check_variant(cx, self.threshold, def, item_name, item.span);
}
}
// be sure we have `self` parameter in this function
if trait_item.kind == (AssocItemKind::Fn { has_self: true }) {
trait_self_ty = Some(
- TraitRef::identity(cx.tcx, trait_item.id.def_id.to_def_id())
+ TraitRef::identity(cx.tcx, trait_item.id.owner_id.to_def_id())
.self_ty()
.skip_binder(),
);
fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) {
if_chain! {
if let ItemKind::Enum(..) | ItemKind::Struct(..) = item.kind;
- if cx.access_levels.is_exported(item.def_id.def_id);
+ if cx.effective_visibilities.is_exported(item.owner_id.def_id);
let attrs = cx.tcx.hir().attrs(item.hir_id());
if !attrs.iter().any(|a| a.has_name(sym::non_exhaustive));
then {
// check for `impl From<???> for ..`
if_chain! {
if let hir::ItemKind::Impl(impl_) = &item.kind;
- if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(item.def_id);
+ if let Some(impl_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id);
if cx.tcx.is_diagnostic_item(sym::From, impl_trait_ref.def_id);
then {
lint_impl_body(cx, item.span, impl_.items);
let body = cx.tcx.hir().body(body_id);
let mut fpu = FindPanicUnwrap {
lcx: cx,
- typeck_results: cx.tcx.typeck(impl_item.id.def_id.def_id),
+ typeck_results: cx.tcx.typeck(impl_item.id.owner_id.def_id),
result: Vec::new(),
};
fpu.visit_expr(body.value);
/// nothing will be suggested, e.g. `println!("{0}={1}", var, 1+2)`.
#[clippy::version = "1.65.0"]
pub UNINLINED_FORMAT_ARGS,
- style,
+ pedantic,
"using non-inlined variables in `format!` calls"
}
&& let Some(into_trait_seg) = hir_trait_ref.path.segments.last()
// `impl Into<target_ty> for self_ty`
&& let Some(GenericArgs { args: [GenericArg::Type(target_ty)], .. }) = into_trait_seg.args
- && let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.def_id)
+ && let Some(middle_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
&& cx.tcx.is_diagnostic_item(sym::Into, middle_trait_ref.def_id)
{
span_lint_and_then(
pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
let attrs = cx.tcx.hir().attrs(item.hir_id());
- let attr = cx.tcx.get_attr(item.def_id.to_def_id(), sym::must_use);
+ let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use);
if let hir::ItemKind::Fn(ref sig, _generics, ref body_id) = item.kind {
- let is_public = cx.access_levels.is_exported(item.def_id.def_id);
+ let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id);
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
if let Some(attr) = attr {
check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
sig.decl,
cx.tcx.hir().body(*body_id),
item.span,
- item.def_id.def_id,
+ item.owner_id.def_id,
item.span.with_hi(sig.decl.output.span().hi()),
"this function could have a `#[must_use]` attribute",
);
pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
if let hir::ImplItemKind::Fn(ref sig, ref body_id) = item.kind {
- let is_public = cx.access_levels.is_exported(item.def_id.def_id);
+ let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id);
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
let attrs = cx.tcx.hir().attrs(item.hir_id());
- let attr = cx.tcx.get_attr(item.def_id.to_def_id(), sym::must_use);
+ let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use);
if let Some(attr) = attr {
check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
- } else if is_public && !is_proc_macro(cx.sess(), attrs) && trait_ref_of_method(cx, item.def_id.def_id).is_none()
+ } else if is_public && !is_proc_macro(cx.sess(), attrs) && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
{
check_must_use_candidate(
cx,
sig.decl,
cx.tcx.hir().body(*body_id),
item.span,
- item.def_id.def_id,
+ item.owner_id.def_id,
item.span.with_hi(sig.decl.output.span().hi()),
"this method could have a `#[must_use]` attribute",
);
pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
if let hir::TraitItemKind::Fn(ref sig, ref eid) = item.kind {
- let is_public = cx.access_levels.is_exported(item.def_id.def_id);
+ let is_public = cx.effective_visibilities.is_exported(item.owner_id.def_id);
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
let attrs = cx.tcx.hir().attrs(item.hir_id());
- let attr = cx.tcx.get_attr(item.def_id.to_def_id(), sym::must_use);
+ let attr = cx.tcx.get_attr(item.owner_id.to_def_id(), sym::must_use);
if let Some(attr) = attr {
check_needless_must_use(cx, sig.decl, item.hir_id(), item.span, fn_header_span, attr);
} else if let hir::TraitFn::Provided(eid) = *eid {
sig.decl,
body,
item.span,
- item.def_id.def_id,
+ item.owner_id.def_id,
item.span.with_hi(sig.decl.output.span().hi()),
"this method could have a `#[must_use]` attribute",
);
|| mutates_static(cx, body)
|| in_external_macro(cx.sess(), item_span)
|| returns_unit(decl)
- || !cx.access_levels.is_exported(item_id)
+ || !cx.effective_visibilities.is_exported(item_id)
|| is_must_use_ty(cx, return_ty(cx, cx.tcx.hir().local_def_id_to_hir_id(item_id)))
{
return;
// primitive types are never mutable
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str => false,
ty::Adt(adt, substs) => {
- tys.insert(adt.did()) && !ty.is_freeze(cx.tcx.at(span), cx.param_env)
+ tys.insert(adt.did()) && !ty.is_freeze(cx.tcx, cx.param_env)
|| KNOWN_WRAPPER_TYS
.iter()
.any(|&sym| cx.tcx.is_diagnostic_item(sym, adt.did()))
pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
if let hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(eid)) = item.kind {
let body = cx.tcx.hir().body(eid);
- check_raw_ptr(cx, sig.header.unsafety, sig.decl, body, item.def_id.def_id);
+ check_raw_ptr(cx, sig.header.unsafety, sig.decl, body, item.owner_id.def_id);
}
}
body: &'tcx hir::Body<'tcx>,
def_id: LocalDefId,
) {
- if unsafety == hir::Unsafety::Normal && cx.access_levels.is_exported(def_id) {
+ if unsafety == hir::Unsafety::Normal && cx.effective_visibilities.is_exported(def_id) {
let raw_ptrs = iter_input_pats(decl, body)
.filter_map(|arg| raw_ptr_arg(cx, arg))
.collect::<HirIdSet>();
pub(super) fn check_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::Item<'tcx>, large_err_threshold: u64) {
if let hir::ItemKind::Fn(ref sig, _generics, _) = item.kind
- && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id.def_id, item.span)
+ && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.owner_id.def_id, item.span)
{
- if cx.access_levels.is_exported(item.def_id.def_id) {
+ if cx.effective_visibilities.is_exported(item.owner_id.def_id) {
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
check_result_unit_err(cx, err_ty, fn_header_span);
}
pub(super) fn check_impl_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::ImplItem<'tcx>, large_err_threshold: u64) {
// Don't lint if method is a trait's implementation, we can't do anything about those
if let hir::ImplItemKind::Fn(ref sig, _) = item.kind
- && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id.def_id, item.span)
- && trait_ref_of_method(cx, item.def_id.def_id).is_none()
+ && let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.owner_id.def_id, item.span)
+ && trait_ref_of_method(cx, item.owner_id.def_id).is_none()
{
- if cx.access_levels.is_exported(item.def_id.def_id) {
+ if cx.effective_visibilities.is_exported(item.owner_id.def_id) {
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
check_result_unit_err(cx, err_ty, fn_header_span);
}
pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &hir::TraitItem<'tcx>, large_err_threshold: u64) {
if let hir::TraitItemKind::Fn(ref sig, _) = item.kind {
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
- if let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.def_id.def_id, item.span) {
- if cx.access_levels.is_exported(item.def_id.def_id) {
+ if let Some((hir_ty, err_ty)) = result_err_ty(cx, sig.decl, item.owner_id.def_id, item.span) {
+ if cx.effective_visibilities.is_exported(item.owner_id.def_id) {
check_result_unit_err(cx, err_ty, fn_header_span);
}
check_result_large_err(cx, err_ty, hir_ty.span, large_err_threshold);
}
}
- if !cx.access_levels.is_exported(item.def_id.def_id) {
+ if !cx.effective_visibilities.is_exported(item.owner_id.def_id) {
return;
}
if is_type_diagnostic_item(cx, return_ty(cx, impl_item.hir_id()), sym::String);
// Filters instances of to_string which are required by a trait
- if trait_ref_of_method(cx, impl_item.def_id.def_id).is_none();
+ if trait_ref_of_method(cx, impl_item.owner_id.def_id).is_none();
then {
show_lint(cx, impl_item);
.expect("Failed to get trait ID of `Display`!");
// Get the real type of 'self'
- let self_type = cx.tcx.fn_sig(item.def_id).input(0);
+ let self_type = cx.tcx.fn_sig(item.owner_id).input(0);
let self_type = self_type.skip_binder().peel_refs();
// Emit either a warning or an error
let name = item.ident.name.as_str();
if matches!(name, "iter" | "iter_mut") {
if let TraitItemKind::Fn(fn_sig, _) = &item.kind {
- check_sig(cx, name, fn_sig, item.def_id.def_id);
+ check_sig(cx, name, fn_sig, item.owner_id.def_id);
}
}
}
)
{
if let ImplItemKind::Fn(fn_sig, _) = &item.kind {
- check_sig(cx, name, fn_sig, item.def_id.def_id);
+ check_sig(cx, name, fn_sig, item.owner_id.def_id);
}
}
}
return;
}
if let ItemKind::Enum(ref def, _) = item.kind {
- let ty = cx.tcx.type_of(item.def_id);
+ let ty = cx.tcx.type_of(item.owner_id);
let Adt(adt, subst) = ty.kind() else {
panic!("already checked whether this is an enum")
};
if item.ident.name == sym::len;
if let ImplItemKind::Fn(sig, _) = &item.kind;
if sig.decl.implicit_self.has_implicit_self();
- if cx.access_levels.is_exported(item.def_id.def_id);
+ if cx.effective_visibilities.is_exported(item.owner_id.def_id);
if matches!(sig.decl.output, FnRetTy::Return(_));
if let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id());
if imp.of_trait.is_none();
if let Some(local_id) = ty_id.as_local();
let ty_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id);
if !is_lint_allowed(cx, LEN_WITHOUT_IS_EMPTY, ty_hir_id);
- if let Some(output) = parse_len_output(cx, cx.tcx.fn_sig(item.def_id).skip_binder());
+ if let Some(output) = parse_len_output(cx, cx.tcx.fn_sig(item.owner_id).skip_binder());
then {
let (name, kind) = match cx.tcx.hir().find(ty_hir_id) {
Some(Node::ForeignItem(x)) => (x.ident.name, "extern type"),
fn is_named_self(cx: &LateContext<'_>, item: &TraitItemRef, name: Symbol) -> bool {
item.ident.name == name
&& if let AssocItemKind::Fn { has_self } = item.kind {
- has_self && { cx.tcx.fn_sig(item.id.def_id).inputs().skip_binder().len() == 1 }
+ has_self && { cx.tcx.fn_sig(item.id.owner_id).inputs().skip_binder().len() == 1 }
} else {
false
}
}
}
- if cx.access_levels.is_exported(visited_trait.def_id.def_id)
+ if cx.effective_visibilities.is_exported(visited_trait.owner_id.def_id)
&& trait_items.iter().any(|i| is_named_self(cx, i, sym::len))
{
let mut current_and_super_traits = DefIdSet::default();
- fill_trait_set(visited_trait.def_id.to_def_id(), &mut current_and_super_traits, cx);
+ fill_trait_set(visited_trait.owner_id.to_def_id(), &mut current_and_super_traits, cx);
let is_empty = sym!(is_empty);
let is_empty_method_found = current_and_super_traits
None,
None,
),
- Some(is_empty) if !cx.access_levels.is_exported(is_empty.def_id.expect_local()) => (
+ Some(is_empty) if !cx.effective_visibilities.is_exported(is_empty.def_id.expect_local()) => (
format!(
"{item_kind} `{}` has a public `len` method, but a private `is_empty` method",
item_name.as_str(),
let span = stmt.span.to(if_.span);
let has_interior_mutability = !cx.typeck_results().node_type(canonical_id).is_freeze(
- cx.tcx.at(span),
+ cx.tcx,
cx.param_env,
);
if has_interior_mutability { return; }
LintId::of(format::USELESS_FORMAT),
LintId::of(format_args::FORMAT_IN_FORMAT_ARGS),
LintId::of(format_args::TO_STRING_IN_FORMAT_ARGS),
- LintId::of(format_args::UNINLINED_FORMAT_ARGS),
LintId::of(format_args::UNUSED_FORMAT_SPECS),
LintId::of(format_impl::PRINT_IN_FORMAT_IMPL),
LintId::of(format_impl::RECURSIVE_FORMAT_IMPL),
LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS),
LintId::of(excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS),
LintId::of(excessive_bools::STRUCT_EXCESSIVE_BOOLS),
+ LintId::of(format_args::UNINLINED_FORMAT_ARGS),
LintId::of(functions::MUST_USE_CANDIDATE),
LintId::of(functions::TOO_MANY_LINES),
LintId::of(if_not_else::IF_NOT_ELSE),
LintId::of(enum_variants::MODULE_INCEPTION),
LintId::of(eta_reduction::REDUNDANT_CLOSURE),
LintId::of(float_literal::EXCESSIVE_PRECISION),
- LintId::of(format_args::UNINLINED_FORMAT_ARGS),
LintId::of(from_over_into::FROM_OVER_INTO),
LintId::of(from_str_radix_10::FROM_STR_RADIX_10),
LintId::of(functions::DOUBLE_MUST_USE),
walk_fn_decl, walk_generic_param, walk_generics, walk_impl_item_ref, walk_item, walk_param_bound,
walk_poly_trait_ref, walk_trait_ref, walk_ty, Visitor,
};
+use rustc_hir::lang_items;
use rustc_hir::FnRetTy::Return;
use rustc_hir::{
BareFnTy, BodyId, FnDecl, GenericArg, GenericBound, GenericParam, GenericParamKind, Generics, Impl, ImplItem,
- ImplItemKind, Item, ItemKind, LangItem, Lifetime, LifetimeName, ParamName, PolyTraitRef, PredicateOrigin, TraitFn,
- TraitItem, TraitItemKind, Ty, TyKind, WherePredicate,
+ ImplItemKind, Item, ItemKind, Lifetime, LifetimeName, ParamName, PolyTraitRef, PredicateOrigin, TraitFn, TraitItem,
+ TraitItemKind, Ty, TyKind, WherePredicate,
};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter as middle_nested_filter;
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) {
if let ImplItemKind::Fn(ref sig, id) = item.kind {
- let report_extra_lifetimes = trait_ref_of_method(cx, item.def_id.def_id).is_none();
+ let report_extra_lifetimes = trait_ref_of_method(cx, item.owner_id.def_id).is_none();
check_fn_inner(
cx,
sig.decl,
lts.iter().collect::<FxHashSet<_>>().len()
}
-const CLOSURE_TRAIT_BOUNDS: [LangItem; 3] = [LangItem::Fn, LangItem::FnMut, LangItem::FnOnce];
-
/// A visitor usable for `rustc_front::visit::walk_ty()`.
struct RefVisitor<'a, 'tcx> {
cx: &'a LateContext<'tcx>,
fn visit_poly_trait_ref(&mut self, poly_tref: &'tcx PolyTraitRef<'tcx>) {
let trait_ref = &poly_tref.trait_ref;
- if CLOSURE_TRAIT_BOUNDS.iter().any(|&item| {
- self.cx
- .tcx
- .lang_items()
- .require(item)
- .map_or(false, |id| Some(id) == trait_ref.trait_def_id())
+ if let Some(id) = trait_ref.trait_def_id() && lang_items::FN_TRAITS.iter().any(|&item| {
+ self.cx.tcx.lang_items().get(item) == Some(id)
}) {
let mut sub_visitor = RefVisitor::new(self.cx);
sub_visitor.visit_trait_ref(trait_ref);
if let Some((id, span)) = iter.next()
&& iter.next().is_none()
{
- self.potential_enums.push((item.def_id.def_id, id, item.span, span));
+ self.potential_enums.push((item.owner_id.def_id, id, item.span, span));
}
}
}
&& match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
&& let hir::ExprKind::MethodCall(_, struct_expr, [], _) = &into_iter_expr.kind
&& let Some(into_iter_def_id) = cx.typeck_results().type_dependent_def_id(into_iter_expr.hir_id)
- && cx.tcx.lang_items().require(hir::LangItem::IntoIterIntoIter).ok() == Some(into_iter_def_id)
+ && Some(into_iter_def_id) == cx.tcx.lang_items().into_iter_fn()
&& match_acceptable_type(cx, left_expr, msrv)
&& SpanlessEq::new(cx).eq_expr(left_expr, struct_expr) {
suggest(cx, parent_expr, left_expr, target_expr);
const GOOD_METHOD_NAME: &'static str;
fn no_op_msg(cx: &LateContext<'_>) -> Option<String> {
- let variant_id = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM).ok()?;
+ let variant_id = cx.tcx.lang_items().get(Self::VARIANT_LANG_ITEM)?;
let item_id = cx.tcx.parent(variant_id);
Some(format!(
"using `{}.{}({})`, which is a no-op",
}
fn lint_msg(cx: &LateContext<'_>) -> Option<String> {
- let variant_id = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM).ok()?;
+ let variant_id = cx.tcx.lang_items().get(Self::VARIANT_LANG_ITEM)?;
let item_id = cx.tcx.parent(variant_id);
Some(format!(
"using `{}.{}(|x| {}(y))`, which is more succinctly expressed as `{}(|x| y)`",
fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) -> bool {
if_chain! {
if let Some(adt) = cx.typeck_results().expr_ty(recv).ty_adt_def();
- if let Ok(vid) = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM);
+ if let Some(vid) = cx.tcx.lang_items().get(Self::VARIANT_LANG_ITEM);
if adt.did() == cx.tcx.parent(vid);
then {} else { return false; }
}
fn is_variant(cx: &LateContext<'_>, res: Res) -> bool {
if let Res::Def(DefKind::Ctor(CtorOf::Variant, CtorKind::Fn), id) = res {
- if let Ok(variant_id) = cx.tcx.lang_items().require(Self::VARIANT_LANG_ITEM) {
+ if let Some(variant_id) = cx.tcx.lang_items().get(Self::VARIANT_LANG_ITEM) {
return cx.tcx.parent(id) == variant_id;
}
}
let name = impl_item.ident.name.as_str();
let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
let item = cx.tcx.hir().expect_item(parent);
- let self_ty = cx.tcx.type_of(item.def_id);
+ let self_ty = cx.tcx.type_of(item.owner_id);
let implements_trait = matches!(item.kind, hir::ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }));
if let hir::ImplItemKind::Fn(ref sig, id) = impl_item.kind {
- let method_sig = cx.tcx.fn_sig(impl_item.def_id);
+ let method_sig = cx.tcx.fn_sig(impl_item.owner_id);
let method_sig = cx.tcx.erase_late_bound_regions(method_sig);
let first_arg_ty_opt = method_sig.inputs().iter().next().copied();
// if this impl block implements a trait, lint in trait definition instead
- if !implements_trait && cx.access_levels.is_exported(impl_item.def_id.def_id) {
+ if !implements_trait && cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) {
// check missing trait implementations
for method_config in &TRAIT_METHODS {
if name == method_config.method_name
if sig.decl.implicit_self.has_implicit_self()
&& !(self.avoid_breaking_exported_api
- && cx.access_levels.is_exported(impl_item.def_id.def_id))
+ && cx.effective_visibilities.is_exported(impl_item.owner_id.def_id))
&& let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next()
&& let Some(first_arg_ty) = first_arg_ty_opt
{
then {
let first_arg_span = first_arg_ty.span;
let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty);
- let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id())
+ let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id())
.self_ty()
.skip_binder();
wrong_self_convention::check(
if item.ident.name == sym::new;
if let TraitItemKind::Fn(_, _) = item.kind;
let ret_ty = return_ty(cx, item.hir_id());
- let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id())
+ let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id())
.self_ty()
.skip_binder();
if !ret_ty.contains(self_ty);
use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait};
use clippy_utils::{fn_def_id, get_parent_expr};
use rustc_errors::Applicability;
-use rustc_hir::{def_id::DefId, Expr, ExprKind, LangItem};
+use rustc_hir::{def_id::DefId, Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_span::{sym, Symbol};
/// Returns true if the named method is `IntoIterator::into_iter`.
pub fn is_into_iter(cx: &LateContext<'_>, callee_def_id: DefId) -> bool {
- cx.tcx.lang_items().require(LangItem::IntoIterIntoIter) == Ok(callee_def_id)
+ Some(callee_def_id) == cx.tcx.lang_items().into_iter_fn()
}
use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty};
use clippy_utils::{meets_msrv, msrvs};
use rustc_errors::Applicability;
-use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, LangItem, Node};
+use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, Node};
use rustc_hir_typeck::{FnCtxt, Inherited};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::LateContext;
Node::Expr(parent_expr) => {
if let Some((callee_def_id, call_substs, recv, call_args)) = get_callee_substs_and_args(cx, parent_expr)
{
- if cx.tcx.lang_items().require(LangItem::IntoFutureIntoFuture) == Ok(callee_def_id) {
+ if Some(callee_def_id) == cx.tcx.lang_items().into_future_fn() {
return false;
}
hir::ItemKind::Fn(..) => {
// ignore main()
if it.ident.name == sym::main {
- let at_root = cx.tcx.local_parent(it.def_id.def_id) == CRATE_DEF_ID;
+ let at_root = cx.tcx.local_parent(it.owner_id.def_id) == CRATE_DEF_ID;
if at_root {
return;
}
| hir::ItemKind::Use(..) => return,
};
- let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id());
+ let (article, desc) = cx.tcx.article_and_description(it.owner_id.to_def_id());
let attrs = cx.tcx.hir().attrs(it.hir_id());
if !is_from_proc_macro(cx, it) {
}
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx hir::TraitItem<'_>) {
- let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id());
+ let (article, desc) = cx.tcx.article_and_description(trait_item.owner_id.to_def_id());
let attrs = cx.tcx.hir().attrs(trait_item.hir_id());
if !is_from_proc_macro(cx, trait_item) {
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) {
// If the method is an impl for a trait, don't doc.
- if let Some(cid) = cx.tcx.associated_item(impl_item.def_id).impl_container(cx.tcx) {
+ if let Some(cid) = cx.tcx.associated_item(impl_item.owner_id).impl_container(cx.tcx) {
if cx.tcx.impl_trait_ref(cid).is_some() {
return;
}
return;
}
- let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id());
+ let (article, desc) = cx.tcx.article_and_description(impl_item.owner_id.to_def_id());
let attrs = cx.tcx.hir().attrs(impl_item.hir_id());
if !is_from_proc_macro(cx, impl_item) {
self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc);
return;
}
- if !cx.access_levels.is_exported(it.def_id.def_id) {
+ if !cx.effective_visibilities.is_exported(it.owner_id.def_id) {
return;
}
match it.kind {
match tit_.kind {
hir::TraitItemKind::Const(..) | hir::TraitItemKind::Type(..) => {},
hir::TraitItemKind::Fn(..) => {
- if cx.tcx.impl_defaultness(tit.id.def_id).has_value() {
+ if cx.tcx.impl_defaultness(tit.id.owner_id).has_value() {
// trait method with default body needs inline in case
// an impl is not provided
let desc = "a default trait method";
}
// If the item being implemented is not exported, then we don't need #[inline]
- if !cx.access_levels.is_exported(impl_item.def_id.def_id) {
+ if !cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) {
return;
}
hir::ImplItemKind::Const(..) | hir::ImplItemKind::Type(_) => return,
};
- let assoc_item = cx.tcx.associated_item(impl_item.def_id);
+ let assoc_item = cx.tcx.associated_item(impl_item.owner_id);
let container_id = assoc_item.container_id(cx.tcx);
let trait_def_id = match assoc_item.container {
TraitContainer => Some(container_id),
};
if let Some(trait_def_id) = trait_def_id {
- if trait_def_id.is_local() && !cx.access_levels.is_exported(impl_item.def_id.def_id) {
+ if trait_def_id.is_local() && !cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) {
// If a trait is being implemented for an item, and the
// trait is not exported, we don't need #[inline]
return;
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'tcx>) {
if let hir::ImplItemKind::Fn(ref sig, ..) = item.kind {
- if trait_ref_of_method(cx, item.def_id.def_id).is_none() {
+ if trait_ref_of_method(cx, item.owner_id.def_id).is_none() {
check_sig(cx, item.hir_id(), sig.decl);
}
}
/// [`Hash`] or [`Ord`].
fn is_interior_mutable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, span: Span) -> bool {
match *ty.kind() {
- Ref(_, inner_ty, mutbl) => mutbl == hir::Mutability::Mut || is_interior_mutable_type(cx, inner_ty, span),
+ Ref(_, inner_ty, mutbl) => {
+ mutbl == hir::Mutability::Mut || is_interior_mutable_type(cx, inner_ty, span)
+ }
Slice(inner_ty) => is_interior_mutable_type(cx, inner_ty, span),
Array(inner_ty, size) => {
size.try_eval_usize(cx.tcx, cx.param_env).map_or(true, |u| u != 0)
&& is_interior_mutable_type(cx, inner_ty, span)
- },
+ }
Tuple(fields) => fields.iter().any(|ty| is_interior_mutable_type(cx, ty, span)),
Adt(def, substs) => {
// Special case for collections in `std` who's impl of `Hash` or `Ord` delegates to
} else {
!ty.has_escaping_bound_vars()
&& cx.tcx.layout_of(cx.param_env.and(ty)).is_ok()
- && !ty.is_freeze(cx.tcx.at(span), cx.param_env)
+ && !ty.is_freeze(cx.tcx, cx.param_env)
}
- },
+ }
_ => false,
}
}
use rustc_middle::ty::{self, TypeVisitable};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::kw;
-use rustc_span::{sym, Span, DUMMY_SP};
+use rustc_span::{sym, Span};
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits;
use rustc_trait_selection::traits::misc::can_type_implement_copy;
if !is_self(arg);
if !ty.is_mutable_ptr();
if !is_copy(cx, ty);
- if ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env);
+ if ty.is_sized(cx.tcx, cx.param_env);
if !allowed_traits.iter().any(|&t| implements_trait(cx, ty, t, &[]));
if !implements_borrow_trait;
if !all_borrowable_trait;
// can't be implemented for unsafe new
return;
}
- if cx.tcx.is_doc_hidden(impl_item.def_id.def_id) {
+ if cx.tcx.is_doc_hidden(impl_item.owner_id.def_id) {
// shouldn't be implemented when it is hidden in docs
return;
}
if_chain! {
if sig.decl.inputs.is_empty();
if name == sym::new;
- if cx.access_levels.is_reachable(impl_item.def_id.def_id);
+ if cx.effective_visibilities.is_reachable(impl_item.owner_id.def_id);
let self_def_id = cx.tcx.hir().get_parent_item(id);
let self_ty = cx.tcx.type_of(self_def_id);
if self_ty == return_ty(cx, id);
use rustc_middle::ty::adjustment::Adjust;
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{sym, InnerSpan, Span, DUMMY_SP};
+use rustc_span::{sym, InnerSpan, Span};
// FIXME: this is a correctness problem but there's no suitable
// warn-by-default category.
// since it works when a pointer indirection involves (`Cell<*const T>`).
// Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option;
// but I'm not sure whether it's a decent way, if possible.
- cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx.at(DUMMY_SP), cx.param_env)
+ cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx, cx.param_env)
}
fn is_value_unfrozen_raw<'tcx>(
if let Some(of_trait_def_id) = of_trait_ref.trait_def_id();
if let Some(of_assoc_item) = cx
.tcx
- .associated_item(impl_item.def_id)
+ .associated_item(impl_item.owner_id)
.trait_item_def_id;
if cx
.tcx
if let Some(trait_id) = trait_ref.trait_def_id();
if send_trait == trait_id;
if hir_impl.polarity == ImplPolarity::Positive;
- if let Some(ty_trait_ref) = cx.tcx.impl_trait_ref(item.def_id);
+ if let Some(ty_trait_ref) = cx.tcx.impl_trait_ref(item.owner_id);
if let self_ty = ty_trait_ref.self_ty();
if let ty::Adt(adt_def, impl_trait_substs) = self_ty.kind();
then {
// `skip_params` is either `0` or `1` to skip the `self` parameter in trait functions.
// It can't be renamed, and it can't be removed without removing it from multiple functions.
let (fn_id, fn_kind, skip_params) = match get_parent_node(cx.tcx, body.value.hir_id) {
- Some(Node::Item(i)) => (i.def_id.to_def_id(), FnKind::Fn, 0),
+ Some(Node::Item(i)) => (i.owner_id.to_def_id(), FnKind::Fn, 0),
Some(Node::TraitItem(&TraitItem {
kind: TraitItemKind::Fn(ref sig, _),
- def_id,
+ owner_id,
..
})) => (
- def_id.to_def_id(),
+ owner_id.to_def_id(),
FnKind::TraitFn,
usize::from(sig.decl.implicit_self.has_implicit_self()),
),
Some(Node::ImplItem(&ImplItem {
kind: ImplItemKind::Fn(ref sig, _),
- def_id,
+ owner_id,
..
})) => {
#[allow(trivial_casts)]
- if let Some(Node::Item(item)) = get_parent_node(cx.tcx, def_id.into())
- && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.def_id)
- && let Some(trait_item_id) = cx.tcx.associated_item(def_id).trait_item_def_id
+ if let Some(Node::Item(item)) = get_parent_node(cx.tcx, owner_id.into())
+ && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id)
+ && let Some(trait_item_id) = cx.tcx.associated_item(owner_id).trait_item_def_id
{
(
trait_item_id,
usize::from(sig.decl.implicit_self.has_implicit_self()),
)
} else {
- (def_id.to_def_id(), FnKind::Fn, 0)
+ (owner_id.to_def_id(), FnKind::Fn, 0)
}
},
_ => return,
let rty = cx.typeck_results().expr_ty(rhs);
if_chain! {
if let Some((_, lang_item)) = binop_traits(op.node);
- if let Ok(trait_id) = cx.tcx.lang_items().require(lang_item);
+ if let Some(trait_id) = cx.tcx.lang_items().get(lang_item);
let parent_fn = cx.tcx.hir().get_parent_item(e.hir_id).def_id;
if trait_ref_of_method(cx, parent_fn)
.map_or(true, |t| t.path.res.def_id() != trait_id);
if let ty::Adt(adt_def, _) = middle_ty.kind();
if let Some(local_did) = adt_def.did().as_local();
let item = cx.tcx.hir().expect_item(local_did);
- let middle_ty_id = item.def_id.to_def_id();
+ let middle_ty_id = item.owner_id.to_def_id();
if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind;
if let Res::Def(_, hir_ty_id) = path.res;
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
if_chain! {
if let ItemKind::Impl(Impl { of_trait: Some(ref trait_ref), items: impl_items, .. }) = item.kind;
- if !cx.tcx.has_attr(item.def_id.to_def_id(), sym::automatically_derived);
+ if !cx.tcx.has_attr(item.owner_id.to_def_id(), sym::automatically_derived);
if let Some(eq_trait) = cx.tcx.lang_items().eq_trait();
if trait_ref.path.res.def_id() == eq_trait;
then {
}
fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, def_id: LocalDefId, decl: &FnDecl<'_>, span: Option<Span>) {
- if self.avoid_breaking_exported_api && cx.access_levels.is_exported(def_id) {
+ if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) {
return;
}
}
if let hir::TraitItemKind::Fn(method_sig, _) = &item.kind {
- self.check_poly_fn(cx, item.def_id.def_id, method_sig.decl, None);
+ self.check_poly_fn(cx, item.owner_id.def_id, method_sig.decl, None);
}
}
check_mut_from_ref(cx, sig, None);
for arg in check_fn_args(
cx,
- cx.tcx.fn_sig(item.def_id).skip_binder().inputs(),
+ cx.tcx.fn_sig(item.owner_id).skip_binder().inputs(),
sig.decl.inputs,
&[],
)
let (item_id, sig, is_trait_item) = match parents.next() {
Some((_, Node::Item(i))) => {
if let ItemKind::Fn(sig, ..) = &i.kind {
- (i.def_id, sig, false)
+ (i.owner_id, sig, false)
} else {
return;
}
return;
}
if let ImplItemKind::Fn(sig, _) = &i.kind {
- (i.def_id, sig, false)
+ (i.owner_id, sig, false)
} else {
return;
}
},
Some((_, Node::TraitItem(i))) => {
if let TraitItemKind::Fn(sig, _) = &i.kind {
- (i.def_id, sig, true)
+ (i.owner_id, sig, true)
} else {
return;
}
then {
let mut applicability = Applicability::MachineApplicable;
let receiver_str = snippet_with_applicability(cx, caller.span, "..", &mut applicability);
- let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx.at(caller.span), cx.param_env) &&
+ let by_ref = !caller_ty.is_copy_modulo_regions(cx.tcx, cx.param_env) &&
!matches!(caller.kind, ExprKind::Call(..) | ExprKind::MethodCall(..));
let sugg = if let Some(else_inner) = r#else {
if eq_expr_value(cx, caller, peel_blocks(else_inner)) {
impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
if_chain! {
- if cx.tcx.visibility(item.def_id.def_id) == ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id());
- if !cx.access_levels.is_exported(item.def_id.def_id) && self.is_exported.last() == Some(&false);
+ if cx.tcx.visibility(item.owner_id.def_id) == ty::Visibility::Restricted(CRATE_DEF_ID.to_def_id());
+ if !cx.effective_visibilities.is_exported(item.owner_id.def_id) && self.is_exported.last() == Some(&false);
if is_not_macro_export(item);
then {
let span = item.span.with_hi(item.ident.span.hi());
- let descr = cx.tcx.def_kind(item.def_id).descr(item.def_id.to_def_id());
+ let descr = cx.tcx.def_kind(item.owner_id).descr(item.owner_id.to_def_id());
span_lint_and_then(
cx,
REDUNDANT_PUB_CRATE,
}
if let ItemKind::Mod { .. } = item.kind {
- self.is_exported.push(cx.access_levels.is_exported(item.def_id.def_id));
+ self.is_exported.push(cx.effective_visibilities.is_exported(item.owner_id.def_id));
}
}
if !in_external_macro(cx.sess(), span);
if decl.implicit_self.has_implicit_self();
// We only show this warning for public exported methods.
- if cx.access_levels.is_exported(fn_def);
+ if cx.effective_visibilities.is_exported(fn_def);
// We don't want to emit this lint if the `#[must_use]` attribute is already there.
if !cx.tcx.hir().attrs(hir_id).iter().any(|attr| attr.has_name(sym::must_use));
if cx.tcx.visibility(fn_def.to_def_id()).is_public();
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'tcx>) {
if let TraitItemKind::Fn(ref sig, _) = item.kind {
- check_method(cx, sig.decl, item.def_id.def_id, item.span, item.hir_id());
+ check_method(cx, sig.decl, item.owner_id.def_id, item.span, item.hir_id());
}
}
}
let mut map = FxHashMap::<Res, ExistingName>::default();
for id in cx.tcx.hir().items() {
- if matches!(cx.tcx.def_kind(id.def_id), DefKind::Impl)
+ if matches!(cx.tcx.def_kind(id.owner_id), DefKind::Impl)
&& let item = cx.tcx.hir().item(id)
&& let ItemKind::Impl(Impl {
items,
let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
let item = cx.tcx.hir().expect_item(parent);
- let self_ty = cx.tcx.type_of(item.def_id);
+ let self_ty = cx.tcx.type_of(item.owner_id);
let ret_ty = return_ty(cx, impl_item.hir_id());
// Do not check trait impls
if_chain! {
if let hir::ExprKind::Binary(binop, _, _) | hir::ExprKind::AssignOp(binop, ..) = expr.kind;
if let Some((binop_trait_lang, op_assign_trait_lang)) = binop_traits(binop.node);
- if let Ok(binop_trait_id) = cx.tcx.lang_items().require(binop_trait_lang);
- if let Ok(op_assign_trait_id) = cx.tcx.lang_items().require(op_assign_trait_lang);
+ if let Some(binop_trait_id) = cx.tcx.lang_items().get(binop_trait_lang);
+ if let Some(op_assign_trait_id) = cx.tcx.lang_items().get(op_assign_trait_lang);
// Check for more than one binary operation in the implemented function
// Linting when multiple operations are involved can result in false positives
(&OP_ASSIGN_TRAITS, SUSPICIOUS_OP_ASSIGN_IMPL),
]
.iter()
- .find(|&(ts, _)| ts.iter().any(|&t| Ok(trait_id) == cx.tcx.lang_items().require(t)));
+ .find(|&(ts, _)| ts.iter().any(|&t| Some(trait_id) == cx.tcx.lang_items().get(t)));
if count_binops(body.value) == 1;
then {
span_lint(
None,
&format!(
"consider annotating `{}` with `#[repr(C)]` or another `repr` attribute",
- cx.tcx.def_path_str(item.def_id.to_def_id())
+ cx.tcx.def_path_str(item.owner_id.to_def_id())
),
);
}
use rustc_lint::LateContext;
use rustc_middle::ty::SubstsRef;
use rustc_middle::ty::{self, IntTy, Ty, TypeAndMut, UintTy};
-use rustc_span::DUMMY_SP;
#[expect(clippy::too_many_lines)]
pub(super) fn check<'tcx>(
// `Repr(C)` <-> unordered type.
// If the first field of the `Repr(C)` type matches then the transmute is ok
- (ReducedTy::OrderedFields(_, Some(from_sub_ty)), ReducedTy::UnorderedFields(to_sub_ty))
- | (ReducedTy::UnorderedFields(from_sub_ty), ReducedTy::OrderedFields(_, Some(to_sub_ty))) => {
+ (
+ ReducedTy::OrderedFields(_, Some(from_sub_ty)),
+ ReducedTy::UnorderedFields(to_sub_ty),
+ )
+ | (
+ ReducedTy::UnorderedFields(from_sub_ty),
+ ReducedTy::OrderedFields(_, Some(to_sub_ty)),
+ ) => {
from_ty = from_sub_ty;
to_ty = to_sub_ty;
continue;
- },
- (ReducedTy::OrderedFields(_, Some(from_sub_ty)), ReducedTy::Other(to_sub_ty)) if reduced_tys.to_fat_ptr => {
+ }
+ (ReducedTy::OrderedFields(_, Some(from_sub_ty)), ReducedTy::Other(to_sub_ty))
+ if reduced_tys.to_fat_ptr =>
+ {
from_ty = from_sub_ty;
to_ty = to_sub_ty;
continue;
- },
+ }
(ReducedTy::Other(from_sub_ty), ReducedTy::OrderedFields(_, Some(to_sub_ty)))
if reduced_tys.from_fat_ptr =>
{
from_ty = from_sub_ty;
to_ty = to_sub_ty;
continue;
- },
+ }
// ptr <-> ptr
(ReducedTy::Other(from_sub_ty), ReducedTy::Other(to_sub_ty))
from_ty = from_sub_ty;
to_ty = to_sub_ty;
continue;
- },
+ }
// fat ptr <-> (*size, *size)
(ReducedTy::Other(_), ReducedTy::UnorderedFields(to_ty))
if reduced_tys.from_fat_ptr && is_size_pair(to_ty) =>
{
return false;
- },
+ }
(ReducedTy::UnorderedFields(from_ty), ReducedTy::Other(_))
if reduced_tys.to_fat_ptr && is_size_pair(from_ty) =>
{
return false;
- },
+ }
// fat ptr -> some struct | some struct -> fat ptr
(ReducedTy::Other(_), _) if reduced_tys.from_fat_ptr => {
&format!("transmute from `{from_ty_orig}` which has an undefined layout"),
|diag| {
if from_ty_orig.peel_refs() != from_ty.peel_refs() {
- diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
+ diag.note(&format!(
+ "the contained type `{from_ty}` has an undefined layout"
+ ));
}
},
);
return true;
- },
+ }
(_, ReducedTy::Other(_)) if reduced_tys.to_fat_ptr => {
span_lint_and_then(
cx,
&format!("transmute to `{to_ty_orig}` which has an undefined layout"),
|diag| {
if to_ty_orig.peel_refs() != to_ty.peel_refs() {
- diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
+ diag.note(&format!(
+ "the contained type `{to_ty}` has an undefined layout"
+ ));
}
},
);
return true;
- },
+ }
- (ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty)) if from_ty != to_ty => {
+ (ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty))
+ if from_ty != to_ty =>
+ {
let same_adt_did = if let (ty::Adt(from_def, from_subs), ty::Adt(to_def, to_subs))
= (from_ty.kind(), to_ty.kind())
&& from_def == to_def
));
} else {
if from_ty_orig.peel_refs() != from_ty {
- diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
+ diag.note(&format!(
+ "the contained type `{from_ty}` has an undefined layout"
+ ));
}
if to_ty_orig.peel_refs() != to_ty {
- diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
+ diag.note(&format!(
+ "the contained type `{to_ty}` has an undefined layout"
+ ));
}
}
},
);
return true;
- },
+ }
(
ReducedTy::UnorderedFields(from_ty),
- ReducedTy::Other(_) | ReducedTy::OrderedFields(..) | ReducedTy::TypeErasure { raw_ptr_only: true },
+ ReducedTy::Other(_)
+ | ReducedTy::OrderedFields(..)
+ | ReducedTy::TypeErasure { raw_ptr_only: true },
) => {
span_lint_and_then(
cx,
&format!("transmute from `{from_ty_orig}` which has an undefined layout"),
|diag| {
if from_ty_orig.peel_refs() != from_ty {
- diag.note(&format!("the contained type `{from_ty}` has an undefined layout"));
+ diag.note(&format!(
+ "the contained type `{from_ty}` has an undefined layout"
+ ));
}
},
);
return true;
- },
+ }
(
- ReducedTy::Other(_) | ReducedTy::OrderedFields(..) | ReducedTy::TypeErasure { raw_ptr_only: true },
+ ReducedTy::Other(_)
+ | ReducedTy::OrderedFields(..)
+ | ReducedTy::TypeErasure { raw_ptr_only: true },
ReducedTy::UnorderedFields(to_ty),
) => {
span_lint_and_then(
&format!("transmute into `{to_ty_orig}` which has an undefined layout"),
|diag| {
if to_ty_orig.peel_refs() != to_ty {
- diag.note(&format!("the contained type `{to_ty}` has an undefined layout"));
+ diag.note(&format!(
+ "the contained type `{to_ty}` has an undefined layout"
+ ));
}
},
);
return true;
- },
+ }
(
- ReducedTy::OrderedFields(..) | ReducedTy::Other(_) | ReducedTy::TypeErasure { raw_ptr_only: true },
- ReducedTy::OrderedFields(..) | ReducedTy::Other(_) | ReducedTy::TypeErasure { raw_ptr_only: true },
+ ReducedTy::OrderedFields(..)
+ | ReducedTy::Other(_)
+ | ReducedTy::TypeErasure { raw_ptr_only: true },
+ ReducedTy::OrderedFields(..)
+ | ReducedTy::Other(_)
+ | ReducedTy::TypeErasure { raw_ptr_only: true },
)
| (ReducedTy::UnorderedFields(_), ReducedTy::UnorderedFields(_)) => {
break;
- },
+ }
}
}
}
/// Remove references so long as both types are references.
-fn reduce_refs<'tcx>(cx: &LateContext<'tcx>, mut from_ty: Ty<'tcx>, mut to_ty: Ty<'tcx>) -> ReducedTys<'tcx> {
+fn reduce_refs<'tcx>(
+ cx: &LateContext<'tcx>,
+ mut from_ty: Ty<'tcx>,
+ mut to_ty: Ty<'tcx>,
+) -> ReducedTys<'tcx> {
let mut from_raw_ptr = false;
let mut to_raw_ptr = false;
- let (from_fat_ptr, to_fat_ptr) = loop {
- break match (from_ty.kind(), to_ty.kind()) {
- (
- &(ty::Ref(_, from_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: from_sub_ty, .. })),
- &(ty::Ref(_, to_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: to_sub_ty, .. })),
- ) => {
- from_raw_ptr = matches!(*from_ty.kind(), ty::RawPtr(_));
- from_ty = from_sub_ty;
- to_raw_ptr = matches!(*to_ty.kind(), ty::RawPtr(_));
- to_ty = to_sub_ty;
- continue;
- },
- (&(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })), _)
- if !unsized_ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env) =>
- {
- (true, false)
- },
- (_, &(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })))
- if !unsized_ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env) =>
- {
- (false, true)
- },
- _ => (false, false),
+ let (from_fat_ptr, to_fat_ptr) =
+ loop {
+ break match (from_ty.kind(), to_ty.kind()) {
+ (
+ &(ty::Ref(_, from_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: from_sub_ty, .. })),
+ &(ty::Ref(_, to_sub_ty, _) | ty::RawPtr(TypeAndMut { ty: to_sub_ty, .. })),
+ ) => {
+ from_raw_ptr = matches!(*from_ty.kind(), ty::RawPtr(_));
+ from_ty = from_sub_ty;
+ to_raw_ptr = matches!(*to_ty.kind(), ty::RawPtr(_));
+ to_ty = to_sub_ty;
+ continue;
+ }
+ (
+ &(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })),
+ _,
+ ) if !unsized_ty.is_sized(cx.tcx, cx.param_env) => (true, false),
+ (
+ _,
+ &(ty::Ref(_, unsized_ty, _) | ty::RawPtr(TypeAndMut { ty: unsized_ty, .. })),
+ ) if !unsized_ty.is_sized(cx.tcx, cx.param_env) => (false, true),
+ _ => (false, false),
+ };
};
- };
- ReducedTys {
- from_ty,
- to_ty,
- from_raw_ptr,
- to_raw_ptr,
- from_fat_ptr,
- to_fat_ptr,
- }
+ ReducedTys { from_ty, to_ty, from_raw_ptr, to_raw_ptr, from_fat_ptr, to_fat_ptr }
}
enum ReducedTy<'tcx> {
return match *ty.kind() {
ty::Array(sub_ty, _) if matches!(sub_ty.kind(), ty::Int(_) | ty::Uint(_)) => {
ReducedTy::TypeErasure { raw_ptr_only: false }
- },
+ }
ty::Array(sub_ty, _) | ty::Slice(sub_ty) => {
ty = sub_ty;
continue;
- },
+ }
ty::Tuple(args) if args.is_empty() => ReducedTy::TypeErasure { raw_ptr_only: false },
ty::Tuple(args) => {
let mut iter = args.iter();
continue;
}
ReducedTy::UnorderedFields(ty)
- },
+ }
ty::Adt(def, substs) if def.is_struct() => {
let mut iter = def
.non_enum_variant()
} else {
ReducedTy::UnorderedFields(ty)
}
- },
- ty::Adt(def, _) if def.is_enum() && (def.variants().is_empty() || is_c_void(cx, ty)) => {
+ }
+ ty::Adt(def, _)
+ if def.is_enum() && (def.variants().is_empty() || is_c_void(cx, ty)) =>
+ {
ReducedTy::TypeErasure { raw_ptr_only: false }
- },
+ }
// TODO: Check if the conversion to or from at least one of a union's fields is valid.
ty::Adt(def, _) if def.is_union() => ReducedTy::TypeErasure { raw_ptr_only: false },
ty::Foreign(_) | ty::Param(_) => ReducedTy::TypeErasure { raw_ptr_only: false },
for (ty1, ty2) in subs1.types().zip(subs2.types()).filter(|(ty1, ty2)| ty1 != ty2) {
match (ty1.kind(), ty2.kind()) {
(ty::Param(_), _) | (_, ty::Param(_)) => (),
- (ty::Adt(adt1, subs1), ty::Adt(adt2, subs2)) if adt1 == adt2 && same_except_params(subs1, subs2) => (),
+ (ty::Adt(adt1, subs1), ty::Adt(adt2, subs2))
+ if adt1 == adt2 && same_except_params(subs1, subs2) =>
+ {
+ ()
+ }
_ => return false,
}
}
use rustc_lint::LateContext;
use rustc_middle::ty::{cast::CastKind, Ty};
use rustc_span::DUMMY_SP;
+use rustc_hir as hir;
// check if the component types of the transmuted collection and the result have different ABI,
// size or alignment
if let Ok(check) = cast::CastCheck::new(
&fn_ctxt, e, from_ty, to_ty,
// We won't show any error to the user, so we don't care what the span is here.
- DUMMY_SP, DUMMY_SP,
+ DUMMY_SP, DUMMY_SP, hir::Constness::NotConst,
) {
let res = check.do_check(&fn_ctxt);
false
};
- let is_exported = cx.access_levels.is_exported(cx.tcx.hir().local_def_id(id));
+ let is_exported = cx.effective_visibilities.is_exported(cx.tcx.hir().local_def_id(id));
self.check_fn_decl(
cx,
}
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) {
- let is_exported = cx.access_levels.is_exported(item.def_id.def_id);
+ let is_exported = cx.effective_visibilities.is_exported(item.owner_id.def_id);
match item.kind {
ItemKind::Static(ty, _, _) | ItemKind::Const(ty, _) => self.check_ty(
}
fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
- let is_exported = cx.access_levels.is_exported(cx.tcx.hir().local_def_id(field.hir_id));
+ let is_exported = cx.effective_visibilities.is_exported(cx.tcx.hir().local_def_id(field.hir_id));
self.check_ty(
cx,
}
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &TraitItem<'_>) {
- let is_exported = cx.access_levels.is_exported(item.def_id.def_id);
+ let is_exported = cx.effective_visibilities.is_exported(item.owner_id.def_id);
let context = CheckTyContext {
is_exported,
use super::{utils, REDUNDANT_ALLOCATION};
-pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, qpath: &QPath<'_>, def_id: DefId) -> bool {
+pub(super) fn check(
+ cx: &LateContext<'_>,
+ hir_ty: &hir::Ty<'_>,
+ qpath: &QPath<'_>,
+ def_id: DefId,
+) -> bool {
let mut applicability = Applicability::MaybeIncorrect;
let outer_sym = if Some(def_id) == cx.tcx.lang_items().owned_box() {
"Box"
hir_ty.span,
&format!("usage of `{outer_sym}<{generic_snippet}>`"),
|diag| {
- diag.span_suggestion(hir_ty.span, "try", format!("{generic_snippet}"), applicability);
+ diag.span_suggestion(
+ hir_ty.span,
+ "try",
+ format!("{generic_snippet}"),
+ applicability,
+ );
diag.note(&format!(
"`{generic_snippet}` is already a pointer, `{outer_sym}<{generic_snippet}>` allocates a pointer on the heap"
));
// Reallocation of a fat pointer causes it to become thin. `hir_ty_to_ty` is safe to use
// here because `mod.rs` guarantees this lint is only run on types outside of bodies and
// is not run on locals.
- if !hir_ty_to_ty(cx.tcx, ty).is_sized(cx.tcx.at(ty.span), cx.param_env) {
+ if !hir_ty_to_ty(cx.tcx, ty).is_sized(cx.tcx, cx.param_env) {
return false;
}
ty.span
- },
+ }
None => return false,
};
if inner_sym == outer_sym {
});
let ty_ty = hir_ty_to_ty(cx.tcx, boxed_ty);
if !ty_ty.has_escaping_bound_vars();
- if ty_ty.is_sized(cx.tcx.at(ty.span), cx.param_env);
+ if ty_ty.is_sized(cx.tcx, cx.param_env);
if let Ok(ty_ty_size) = cx.layout_of(ty_ty).map(|l| l.size.bytes());
if ty_ty_size <= box_size_threshold;
then {
use if_chain::if_chain;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
-use rustc_hir::{BorrowKind, Expr, ExprKind, LangItem, Mutability};
+use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
);
} else {
if_chain! {
- if cx.tcx.lang_items().require(LangItem::FromFrom).ok() == Some(fun_def_id);
+ if Some(fun_def_id) == cx.tcx.lang_items().from_fn();
if let [.., last_arg] = args;
if let ExprKind::Lit(spanned) = &last_arg.kind;
if let LitKind::Str(symbol, _) = spanned.node;
match fn_kind {
FnKind::ItemFn(..) | FnKind::Method(..) => {
let def_id = cx.tcx.hir().local_def_id(hir_id);
- if self.avoid_breaking_exported_api && cx.access_levels.is_exported(def_id) {
+ if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id) {
return;
}
},
use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, paths, peel_ref_operators};
use rustc_ast::Mutability;
use rustc_hir::intravisit::{walk_expr, Visitor};
-use rustc_hir::lang_items::LangItem;
use rustc_hir::{Block, Expr, ExprKind, HirId, Local, Node, PatKind, PathSegment, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter::OnlyBodies;
// If the Peekable is passed to a function, stop
ExprKind::Call(_, args) => {
if let Some(func_did) = fn_def_id(self.cx, expr)
- && let Ok(into_iter_did) = self
+ && let Some(into_iter_did) = self
.cx
.tcx
.lang_items()
- .require(LangItem::IntoIterIntoIter)
+ .into_iter_fn()
&& func_did == into_iter_did
{
// Probably a for loop desugar, stop searching
}
let parent = cx.tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
let parent_item = cx.tcx.hir().expect_item(parent);
- let assoc_item = cx.tcx.associated_item(impl_item.def_id);
+ let assoc_item = cx.tcx.associated_item(impl_item.owner_id);
if_chain! {
if let ItemKind::Impl(Impl { of_trait: None, .. }) = parent_item.kind;
if assoc_item.fn_has_self_parameter;
if let ImplItemKind::Fn(.., body_id) = &impl_item.kind;
- if !cx.access_levels.is_exported(impl_item.def_id.def_id) || !self.avoid_breaking_exported_api;
+ if !cx.effective_visibilities.is_exported(impl_item.owner_id.def_id) || !self.avoid_breaking_exported_api;
let body = cx.tcx.hir().body(*body_id);
if let [self_param, ..] = body.params;
if !is_local_used(cx, body, self_param.pat.hir_id);
fn lint_impl_body<'tcx>(cx: &LateContext<'tcx>, impl_span: Span, impl_item: &'tcx hir::ImplItem<'_>) {
if let ImplItemKind::Fn(_, body_id) = impl_item.kind {
let body = cx.tcx.hir().body(body_id);
- let typeck = cx.tcx.typeck(impl_item.def_id.def_id);
+ let typeck = cx.tcx.typeck(impl_item.owner_id.def_id);
let mut result = Vec::new();
let _: Option<!> = for_each_expr(body.value, |e| {
// check for `expect`
fn check_item(&mut self, cx: &LateContext<'_>, it: &Item<'_>) {
// do not lint public items or in macros
if in_external_macro(cx.sess(), it.span)
- || (self.avoid_breaking_exported_api && cx.access_levels.is_exported(it.def_id.def_id))
+ || (self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(it.owner_id.def_id))
{
return;
}
if !is_from_proc_macro(cx, item); // expensive, should be last check
then {
StackItem::Check {
- impl_id: item.def_id.def_id,
+ impl_id: item.owner_id.def_id,
in_body: 0,
types_to_skip: std::iter::once(self_ty.hir_id).collect(),
}
// trait, not in the impl of the trait.
let trait_method = cx
.tcx
- .associated_item(impl_item.def_id)
+ .associated_item(impl_item.owner_id)
.trait_item_def_id
.expect("impl method matches a trait method");
let trait_method_sig = cx.tcx.fn_sig(trait_method);
use clippy_utils::{get_parent_expr, is_trait_method, match_def_path, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, HirId, LangItem, MatchSource};
+use rustc_hir::{Expr, ExprKind, HirId, MatchSource};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_tool_lint, impl_lint_pass};
}
if_chain! {
- if cx.tcx.lang_items().require(LangItem::FromFrom).ok() == Some(def_id);
+ if Some(def_id) == cx.tcx.lang_items().from_fn();
if same_type_and_consts(a, b);
then {
has_ctor,
),
(0, Item::LangItem(item)) => (
- format!("{cx_snip}.tcx.lang_items().require(LangItem::{item}).ok() == Some({def_snip})"),
+ format!("{cx_snip}.tcx.lang_items().get(LangItem::{item}) == Some({def_snip})"),
has_ctor,
),
// match_trait_method
(3, Item::LangItem(item)) => (
format!(
"path_res({cx_snip}, {def_snip}).opt_def_id()\
- .map_or(false, |id| {cx_snip}.tcx.lang_items().require(LangItem::{item}).ok() == Some(id))",
+ .map_or(false, |id| {cx_snip}.tcx.lang_items().get(LangItem::{item}) == Some(id))",
),
false,
),
if is_test_module_or_function(cx.tcx, item) {
self.test_modules_deep = self.test_modules_deep.saturating_add(1);
}
- let module = cx.tcx.parent_module_from_def_id(item.def_id.def_id);
- if cx.tcx.visibility(item.def_id.def_id) != ty::Visibility::Restricted(module.to_def_id()) {
+ let module = cx.tcx.parent_module_from_def_id(item.owner_id.def_id);
+ if cx.tcx.visibility(item.owner_id.def_id) != ty::Visibility::Restricted(module.to_def_id()) {
return;
}
if_chain! {
if let ItemKind::Use(use_path, UseKind::Glob) = &item.kind;
if self.warn_on_all || !self.check_exceptions(item, use_path.segments);
- let used_imports = cx.tcx.names_imported_by_glob_use(item.def_id.def_id);
+ let used_imports = cx.tcx.names_imported_by_glob_use(item.owner_id.def_id);
if !used_imports.is_empty(); // Already handled by `unused_imports`
then {
let mut applicability = Applicability::MachineApplicable;
/// For example, use this to check whether a function call or a pattern is `Some(..)`.
pub fn is_res_lang_ctor(cx: &LateContext<'_>, res: Res, lang_item: LangItem) -> bool {
if let Res::Def(DefKind::Ctor(..), id) = res
- && let Ok(lang_id) = cx.tcx.lang_items().require(lang_item)
+ && let Some(lang_id) = cx.tcx.lang_items().get(lang_item)
&& let Some(id) = cx.tcx.opt_parent(id)
{
id == lang_id
_ => did,
};
- cx.tcx.lang_items().require(item).map_or(false, |id| id == did)
+ cx.tcx.lang_items().get(item) == Some(did)
}
pub fn is_unit_expr(expr: &Expr<'_>) -> bool {
Entry::Vacant(entry) => {
let mut names = Vec::new();
for id in tcx.hir().module_items(module) {
- if matches!(tcx.def_kind(id.def_id), DefKind::Const)
+ if matches!(tcx.def_kind(id.owner_id), DefKind::Const)
&& let item = tcx.hir().item(id)
&& let ItemKind::Const(ty, _body) = item.kind {
if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
};
use rustc_middle::ty::{GenericArg, GenericArgKind};
use rustc_span::symbol::Ident;
-use rustc_span::{sym, Span, Symbol, DUMMY_SP};
+use rustc_span::{sym, Span, Symbol};
use rustc_target::abi::{Size, VariantIdx};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::query::normalize::AtExt;
// Checks if the given type implements copy.
pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
- ty.is_copy_modulo_regions(cx.tcx.at(DUMMY_SP), cx.param_env)
+ ty.is_copy_modulo_regions(cx.tcx, cx.param_env)
}
/// This checks whether a given type is known to implement Debug.
/// Returns `false` if the `LangItem` is not defined.
pub fn is_type_lang_item(cx: &LateContext<'_>, ty: Ty<'_>, lang_item: hir::LangItem) -> bool {
match ty.kind() {
- ty::Adt(adt, _) => cx
- .tcx
- .lang_items()
- .require(lang_item)
- .map_or(false, |li| li == adt.did()),
+ ty::Adt(adt, _) => cx.tcx.lang_items().get(lang_item) == Some(adt.did()),
_ => false,
}
}
use std::env;
use std::ops::Deref;
use std::panic;
-use std::path::{Path, PathBuf};
-use std::process::{exit, Command};
+use std::path::Path;
+use std::process::exit;
use std::sync::LazyLock;
/// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If
false,
None,
false,
+ false,
));
let handler = rustc_errors::Handler::with_emitter(true, None, emitter);
interface::try_print_query_stack(&handler, num_frames);
}
-fn toolchain_path(home: Option<String>, toolchain: Option<String>) -> Option<PathBuf> {
- home.and_then(|home| {
- toolchain.map(|toolchain| {
- let mut path = PathBuf::from(home);
- path.push("toolchains");
- path.push(toolchain);
- path
- })
- })
-}
-
#[allow(clippy::too_many_lines)]
pub fn main() {
rustc_driver::init_rustc_env_logger();
exit(rustc_driver::catch_with_exit_code(move || {
let mut orig_args: Vec<String> = env::args().collect();
- // Get the sysroot, looking from most specific to this invocation to the least:
- // - command line
- // - runtime environment
- // - SYSROOT
- // - RUSTUP_HOME, MULTIRUST_HOME, RUSTUP_TOOLCHAIN, MULTIRUST_TOOLCHAIN
- // - sysroot from rustc in the path
- // - compile-time environment
- // - SYSROOT
- // - RUSTUP_HOME, MULTIRUST_HOME, RUSTUP_TOOLCHAIN, MULTIRUST_TOOLCHAIN
- let sys_root_arg = arg_value(&orig_args, "--sysroot", |_| true);
- let have_sys_root_arg = sys_root_arg.is_some();
- let sys_root = sys_root_arg
- .map(PathBuf::from)
- .or_else(|| std::env::var("SYSROOT").ok().map(PathBuf::from))
- .or_else(|| {
- let home = std::env::var("RUSTUP_HOME")
- .or_else(|_| std::env::var("MULTIRUST_HOME"))
- .ok();
- let toolchain = std::env::var("RUSTUP_TOOLCHAIN")
- .or_else(|_| std::env::var("MULTIRUST_TOOLCHAIN"))
- .ok();
- toolchain_path(home, toolchain)
- })
- .or_else(|| {
- Command::new("rustc")
- .arg("--print")
- .arg("sysroot")
- .output()
- .ok()
- .and_then(|out| String::from_utf8(out.stdout).ok())
- .map(|s| PathBuf::from(s.trim()))
- })
- .or_else(|| option_env!("SYSROOT").map(PathBuf::from))
- .or_else(|| {
- let home = option_env!("RUSTUP_HOME")
- .or(option_env!("MULTIRUST_HOME"))
- .map(ToString::to_string);
- let toolchain = option_env!("RUSTUP_TOOLCHAIN")
- .or(option_env!("MULTIRUST_TOOLCHAIN"))
- .map(ToString::to_string);
- toolchain_path(home, toolchain)
- })
- .map(|pb| pb.to_string_lossy().to_string())
- .expect("need to specify SYSROOT env var during clippy compilation, or use rustup or multirust");
-
// make "clippy-driver --rustc" work like a subcommand that passes further args to "rustc"
// for example `clippy-driver --rustc --version` will print the rustc version that clippy-driver
// uses
orig_args.remove(pos);
orig_args[0] = "rustc".to_string();
- // if we call "rustc", we need to pass --sysroot here as well
- let mut args: Vec<String> = orig_args.clone();
- if !have_sys_root_arg {
- args.extend(vec!["--sysroot".into(), sys_root]);
- };
-
- return rustc_driver::RunCompiler::new(&args, &mut DefaultCallbacks).run();
+ return rustc_driver::RunCompiler::new(&orig_args, &mut DefaultCallbacks).run();
}
if orig_args.iter().any(|a| a == "--version" || a == "-V") {
exit(0);
}
- // this conditional check for the --sysroot flag is there so users can call
- // `clippy_driver` directly
- // without having to pass --sysroot or anything
- let mut args: Vec<String> = orig_args.clone();
- if !have_sys_root_arg {
- args.extend(vec!["--sysroot".into(), sys_root]);
- };
-
let mut no_deps = false;
let clippy_args_var = env::var("CLIPPY_ARGS").ok();
let clippy_args = clippy_args_var
let clippy_enabled = !cap_lints_allow && (!no_deps || in_primary_package);
if clippy_enabled {
+ let mut args: Vec<String> = orig_args.clone();
args.extend(clippy_args);
rustc_driver::RunCompiler::new(&args, &mut ClippyCallbacks { clippy_args_var }).run()
} else {
- rustc_driver::RunCompiler::new(&args, &mut RustcCallbacks { clippy_args_var }).run()
+ rustc_driver::RunCompiler::new(&orig_args, &mut RustcCallbacks { clippy_args_var }).run()
}
}))
}
--- /dev/null
+// compile-flags: -Z track-diagnostics
+// error-pattern: created at
+
+// Normalize the emitted location so this doesn't need
+// updating everytime someone adds or removes a line.
+// normalize-stderr-test ".rs:\d+:\d+" -> ".rs:LL:CC"
+
+struct A;
+struct B;
+const S: A = B;
+
+fn main() {}
--- /dev/null
+error[E0308]: mismatched types
+ --> $DIR/track-diagnostics.rs:LL:CC
+ |
+LL | const S: A = B;
+ | ^ expected struct `A`, found struct `B`
+-Ztrack-diagnostics: created at compiler/rustc_infer/src/infer/error_reporting/mod.rs:LL:CC
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff = "0.1.10"
unified-diff = "0.2.1"
getopts = "0.2"
+miropt-test-tools = { path = "../miropt-test-tools" }
tracing = "0.1"
tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
regex = "1.0"
use std::ffi::OsString;
use std::fmt;
+use std::iter;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str::FromStr;
-use crate::util::PathBufExt;
+use crate::util::{add_dylib_path, PathBufExt};
use lazycell::LazyCell;
use test::ColorConfig;
pub runtool: Option<String>,
/// Flags to pass to the compiler when building for the host
- pub host_rustcflags: Option<String>,
+ pub host_rustcflags: Vec<String>,
/// Flags to pass to the compiler when building for the target
- pub target_rustcflags: Option<String>,
+ pub target_rustcflags: Vec<String>,
/// Whether tests should be optimized by default. Individual test-suites and test files may
/// override this setting.
}
fn target_cfg(&self) -> &TargetCfg {
- self.target_cfg
- .borrow_with(|| TargetCfg::new(&self.rustc_path, &self.target, &self.target_rustcflags))
+ self.target_cfg.borrow_with(|| TargetCfg::new(self))
}
pub fn matches_arch(&self, arch: &str) -> bool {
}
impl TargetCfg {
- fn new(rustc_path: &Path, target: &str, target_rustcflags: &Option<String>) -> TargetCfg {
- let output = match Command::new(rustc_path)
+ fn new(config: &Config) -> TargetCfg {
+ let mut command = Command::new(&config.rustc_path);
+ add_dylib_path(&mut command, iter::once(&config.compile_lib_path));
+ let output = match command
.arg("--print=cfg")
.arg("--target")
- .arg(target)
- .args(target_rustcflags.into_iter().map(|s| s.split_whitespace()).flatten())
+ .arg(&config.target)
+ .args(&config.target_rustcflags)
.output()
{
Ok(output) => output,
- Err(e) => panic!("error: failed to get cfg info from {:?}: {e}", rustc_path),
+ Err(e) => panic!("error: failed to get cfg info from {:?}: {e}", config.rustc_path),
};
if !output.status.success() {
panic!(
"error: failed to get cfg info from {:?}\n--- stdout\n{}\n--- stderr\n{}",
- rustc_path,
+ config.rustc_path,
String::from_utf8(output.stdout).unwrap(),
String::from_utf8(output.stderr).unwrap(),
);
}),
logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)),
runtool: matches.opt_str("runtool"),
- host_rustcflags: Some(matches.opt_strs("host-rustcflags").join(" ")),
- target_rustcflags: Some(matches.opt_strs("target-rustcflags").join(" ")),
+ host_rustcflags: matches.opt_strs("host-rustcflags"),
+ target_rustcflags: matches.opt_strs("target-rustcflags"),
optimize_tests: matches.opt_present("optimize-tests"),
target,
host: opt_str2(matches.opt_str("host")),
format!("force_pass_mode: {}", opt_str(&config.force_pass_mode.map(|m| format!("{}", m))),),
);
logv(c, format!("runtool: {}", opt_str(&config.runtool)));
- logv(c, format!("host-rustcflags: {}", opt_str(&config.host_rustcflags)));
- logv(c, format!("target-rustcflags: {}", opt_str(&config.target_rustcflags)));
+ logv(c, format!("host-rustcflags: {:?}", config.host_rustcflags));
+ logv(c, format!("target-rustcflags: {:?}", config.target_rustcflags));
logv(c, format!("target: {}", config.target));
logv(c, format!("host: {}", config.host));
logv(c, format!("android-cross-path: {:?}", config.android_cross_path.display()));
use crate::header::TestProps;
use crate::json;
use crate::read2::read2_abbreviated;
-use crate::util::{logv, PathBufExt};
+use crate::util::{add_dylib_path, dylib_env_var, logv, PathBufExt};
use crate::ColorConfig;
use regex::{Captures, Regex};
use rustfix::{apply_suggestions, get_suggestions_from_json, Filter};
use std::hash::{Hash, Hasher};
use std::io::prelude::*;
use std::io::{self, BufReader};
+use std::iter;
use std::path::{Path, PathBuf};
use std::process::{Child, Command, ExitStatus, Output, Stdio};
use std::str;
f()
}
-/// The name of the environment variable that holds dynamic library locations.
-pub fn dylib_env_var() -> &'static str {
- if cfg!(windows) {
- "PATH"
- } else if cfg!(target_os = "macos") {
- "DYLD_LIBRARY_PATH"
- } else if cfg!(target_os = "haiku") {
- "LIBRARY_PATH"
- } else {
- "LD_LIBRARY_PATH"
- }
-}
-
/// The platform-specific library name
pub fn get_lib_name(lib: &str, dylib: bool) -> String {
// In some casess (e.g. MUSL), we build a static
Disabled,
}
-/// Should `--emit metadata` be used?
+/// What value should be passed to `--emit`?
#[derive(Copy, Clone)]
-enum EmitMetadata {
- Yes,
- No,
+enum Emit {
+ None,
+ Metadata,
+ LlvmIr,
+ Asm,
}
impl<'test> TestCx<'test> {
}
let should_run = self.run_if_enabled();
- let mut proc_res = self.compile_test(should_run, EmitMetadata::No);
+ let mut proc_res = self.compile_test(should_run, Emit::None);
if !proc_res.status.success() {
self.fatal_proc_rec("compilation failed!", &proc_res);
.arg(&aux_dir)
.args(&self.props.compile_flags)
.envs(self.props.rustc_env.clone());
- self.maybe_add_external_args(
- &mut rustc,
- self.split_maybe_args(&self.config.target_rustcflags),
- );
+ self.maybe_add_external_args(&mut rustc, &self.config.target_rustcflags);
let src = match read_from {
ReadFrom::Stdin(src) => Some(src),
.arg("-L")
.arg(aux_dir);
self.set_revision_flags(&mut rustc);
- self.maybe_add_external_args(
- &mut rustc,
- self.split_maybe_args(&self.config.target_rustcflags),
- );
+ self.maybe_add_external_args(&mut rustc, &self.config.target_rustcflags);
rustc.args(&self.props.compile_flags);
self.compose_and_run_compiler(rustc, Some(src))
// compile test file (it should have 'compile-flags:-g' in the header)
let should_run = self.run_if_enabled();
- let compile_result = self.compile_test(should_run, EmitMetadata::No);
+ let compile_result = self.compile_test(should_run, Emit::None);
if !compile_result.status.success() {
self.fatal_proc_rec("compilation failed!", &compile_result);
}
// compile test file (it should have 'compile-flags:-g' in the header)
let should_run = self.run_if_enabled();
- let compiler_run_result = self.compile_test(should_run, EmitMetadata::No);
+ let compiler_run_result = self.compile_test(should_run, Emit::None);
if !compiler_run_result.status.success() {
self.fatal_proc_rec("compilation failed!", &compiler_run_result);
}
fn run_debuginfo_lldb_test_no_opt(&self) {
// compile test file (it should have 'compile-flags:-g' in the header)
let should_run = self.run_if_enabled();
- let compile_result = self.compile_test(should_run, EmitMetadata::No);
+ let compile_result = self.compile_test(should_run, Emit::None);
if !compile_result.status.success() {
self.fatal_proc_rec("compilation failed!", &compile_result);
}
ProcRes { status, stdout: out, stderr: err, cmdline: format!("{:?}", cmd) }
}
- fn cleanup_debug_info_options(&self, options: &Option<String>) -> Option<String> {
- if options.is_none() {
- return None;
- }
-
+ fn cleanup_debug_info_options(&self, options: &Vec<String>) -> Vec<String> {
// Remove options that are either unwanted (-O) or may lead to duplicates due to RUSTFLAGS.
let options_to_remove = ["-O".to_owned(), "-g".to_owned(), "--debuginfo".to_owned()];
- let new_options = self
- .split_maybe_args(options)
- .into_iter()
- .filter(|x| !options_to_remove.contains(x))
- .collect::<Vec<String>>();
- Some(new_options.join(" "))
+ options.iter().filter(|x| !options_to_remove.contains(x)).map(|x| x.clone()).collect()
}
- fn maybe_add_external_args(&self, cmd: &mut Command, args: Vec<String>) {
+ fn maybe_add_external_args(&self, cmd: &mut Command, args: &Vec<String>) {
// Filter out the arguments that should not be added by runtest here.
//
// Notable use-cases are: do not add our optimisation flag if
}
}
- fn should_emit_metadata(&self, pm: Option<PassMode>) -> EmitMetadata {
+ fn should_emit_metadata(&self, pm: Option<PassMode>) -> Emit {
match (pm, self.props.fail_mode, self.config.mode) {
- (Some(PassMode::Check), ..) | (_, Some(FailMode::Check), Ui) => EmitMetadata::Yes,
- _ => EmitMetadata::No,
+ (Some(PassMode::Check), ..) | (_, Some(FailMode::Check), Ui) => Emit::Metadata,
+ _ => Emit::None,
}
}
- fn compile_test(&self, will_execute: WillExecute, emit_metadata: EmitMetadata) -> ProcRes {
- self.compile_test_general(will_execute, emit_metadata, self.props.local_pass_mode())
+ fn compile_test(&self, will_execute: WillExecute, emit: Emit) -> ProcRes {
+ self.compile_test_general(will_execute, emit, self.props.local_pass_mode())
}
fn compile_test_general(
&self,
will_execute: WillExecute,
- emit_metadata: EmitMetadata,
+ emit: Emit,
local_pm: Option<PassMode>,
) -> ProcRes {
// Only use `make_exe_name` when the test ends up being executed.
_ => AllowUnused::No,
};
- let mut rustc =
- self.make_compile_args(&self.testpaths.file, output_file, emit_metadata, allow_unused);
-
- rustc.arg("-L").arg(&self.aux_output_dir_name());
+ let rustc = self.make_compile_args(
+ &self.testpaths.file,
+ output_file,
+ emit,
+ allow_unused,
+ LinkToAux::Yes,
+ );
self.compose_and_run_compiler(rustc, None)
}
// Create the directory for the stdout/stderr files.
create_dir_all(aux_cx.output_base_dir()).unwrap();
let input_file = &aux_testpaths.file;
- let mut aux_rustc =
- aux_cx.make_compile_args(input_file, aux_output, EmitMetadata::No, AllowUnused::No);
+ let mut aux_rustc = aux_cx.make_compile_args(
+ input_file,
+ aux_output,
+ Emit::None,
+ AllowUnused::No,
+ LinkToAux::No,
+ );
for key in &aux_props.unset_rustc_env {
aux_rustc.env_remove(key);
// Need to be sure to put both the lib_path and the aux path in the dylib
// search path for the child.
- let mut path =
- env::split_paths(&env::var_os(dylib_env_var()).unwrap_or_default()).collect::<Vec<_>>();
- if let Some(p) = aux_path {
- path.insert(0, PathBuf::from(p))
- }
- path.insert(0, PathBuf::from(lib_path));
-
- // Add the new dylib search path var
- let newpath = env::join_paths(&path).unwrap();
- command.env(dylib_env_var(), newpath);
+ add_dylib_path(&mut command, iter::once(lib_path).chain(aux_path));
let mut child = disable_error_reporting(|| command.spawn())
.unwrap_or_else(|_| panic!("failed to exec `{:?}`", &command));
&self,
input_file: &Path,
output_file: TargetLocation,
- emit_metadata: EmitMetadata,
+ emit: Emit,
allow_unused: AllowUnused,
+ link_to_aux: LinkToAux,
) -> Command {
let is_aux = input_file.components().map(|c| c.as_os_str()).any(|c| c == "auxiliary");
let is_rustdoc = self.is_rustdoc() && !is_aux;
}
}
- if let (false, EmitMetadata::Yes) = (is_rustdoc, emit_metadata) {
- rustc.args(&["--emit", "metadata"]);
+ match emit {
+ Emit::None => {}
+ Emit::Metadata if is_rustdoc => {}
+ Emit::Metadata => {
+ rustc.args(&["--emit", "metadata"]);
+ }
+ Emit::LlvmIr => {
+ rustc.args(&["--emit", "llvm-ir"]);
+ }
+ Emit::Asm => {
+ rustc.args(&["--emit", "asm"]);
+ }
}
if !is_rustdoc {
}
if self.props.force_host {
- self.maybe_add_external_args(
- &mut rustc,
- self.split_maybe_args(&self.config.host_rustcflags),
- );
+ self.maybe_add_external_args(&mut rustc, &self.config.host_rustcflags);
} else {
- self.maybe_add_external_args(
- &mut rustc,
- self.split_maybe_args(&self.config.target_rustcflags),
- );
+ self.maybe_add_external_args(&mut rustc, &self.config.target_rustcflags);
if !is_rustdoc {
if let Some(ref linker) = self.config.linker {
rustc.arg(format!("-Clinker={}", linker));
rustc.arg("-Ctarget-feature=-crt-static");
}
+ if let LinkToAux::Yes = link_to_aux {
+ rustc.arg("-L").arg(self.aux_output_dir_name());
+ }
+
rustc.args(&self.props.compile_flags);
rustc
// codegen tests (using FileCheck)
fn compile_test_and_save_ir(&self) -> ProcRes {
- let aux_dir = self.aux_output_dir_name();
-
let output_file = TargetLocation::ThisDirectory(self.output_base_dir());
let input_file = &self.testpaths.file;
- let mut rustc =
- self.make_compile_args(input_file, output_file, EmitMetadata::No, AllowUnused::No);
- rustc.arg("-L").arg(aux_dir).arg("--emit=llvm-ir");
+ let rustc = self.make_compile_args(
+ input_file,
+ output_file,
+ Emit::LlvmIr,
+ AllowUnused::No,
+ LinkToAux::Yes,
+ );
self.compose_and_run_compiler(rustc, None)
}
let output_file = TargetLocation::ThisFile(output_path.clone());
let input_file = &self.testpaths.file;
- let mut rustc =
- self.make_compile_args(input_file, output_file, EmitMetadata::No, AllowUnused::No);
-
- rustc.arg("-L").arg(self.aux_output_dir_name());
+ let mut emit = Emit::None;
match self.props.assembly_output.as_ref().map(AsRef::as_ref) {
Some("emit-asm") => {
- rustc.arg("--emit=asm");
+ emit = Emit::Asm;
}
Some("ptx-linker") => {
None => self.fatal("missing 'assembly-output' header"),
}
+ let rustc =
+ self.make_compile_args(input_file, output_file, emit, AllowUnused::No, LinkToAux::Yes);
+
(self.compose_and_run_compiler(rustc, None), output_path)
}
let mut rustc = new_rustdoc.make_compile_args(
&new_rustdoc.testpaths.file,
output_file,
- EmitMetadata::No,
+ Emit::None,
AllowUnused::Yes,
+ LinkToAux::Yes,
);
- rustc.arg("-L").arg(&new_rustdoc.aux_output_dir_name());
new_rustdoc.build_all_auxiliary(&mut rustc);
let proc_res = new_rustdoc.document(&compare_dir);
fn run_codegen_units_test(&self) {
assert!(self.revision.is_none(), "revisions not relevant here");
- let proc_res = self.compile_test(WillExecute::No, EmitMetadata::No);
+ let proc_res = self.compile_test(WillExecute::No, Emit::None);
if !proc_res.status.success() {
self.fatal_proc_rec("compilation failed!", &proc_res);
if let Some(FailMode::Build) = self.props.fail_mode {
// Make sure a build-fail test cannot fail due to failing analysis (e.g. typeck).
let pm = Some(PassMode::Check);
- let proc_res = self.compile_test_general(WillExecute::No, EmitMetadata::Yes, pm);
+ let proc_res = self.compile_test_general(WillExecute::No, Emit::Metadata, pm);
self.check_if_test_should_compile(&proc_res, pm);
}
if self.props.run_rustfix && self.config.compare_mode.is_none() {
// And finally, compile the fixed code and make sure it both
// succeeds and has no diagnostics.
- let mut rustc = self.make_compile_args(
+ let rustc = self.make_compile_args(
&self.testpaths.file.with_extension(UI_FIXED),
TargetLocation::ThisFile(self.make_exe_name()),
emit_metadata,
AllowUnused::No,
+ LinkToAux::Yes,
);
- rustc.arg("-L").arg(&self.aux_output_dir_name());
let res = self.compose_and_run_compiler(rustc, None);
if !res.status.success() {
self.fatal_proc_rec("failed to compile fixed code", &res);
}
}
- for l in test_file_contents.lines() {
- if l.starts_with("// EMIT_MIR ") {
- let test_name = l.trim_start_matches("// EMIT_MIR ").trim();
- let mut test_names = test_name.split(' ');
- // sometimes we specify two files so that we get a diff between the two files
- let test_name = test_names.next().unwrap();
- let mut expected_file;
- let from_file;
- let to_file;
-
- if test_name.ends_with(".diff") {
- let trimmed = test_name.trim_end_matches(".diff");
- let test_against = format!("{}.after.mir", trimmed);
- from_file = format!("{}.before.mir", trimmed);
- expected_file = format!("{}{}.diff", trimmed, bit_width);
- assert!(
- test_names.next().is_none(),
- "two mir pass names specified for MIR diff"
- );
- to_file = Some(test_against);
- } else if let Some(first_pass) = test_names.next() {
- let second_pass = test_names.next().unwrap();
- assert!(
- test_names.next().is_none(),
- "three mir pass names specified for MIR diff"
- );
- expected_file =
- format!("{}{}.{}-{}.diff", test_name, bit_width, first_pass, second_pass);
- let second_file = format!("{}.{}.mir", test_name, second_pass);
- from_file = format!("{}.{}.mir", test_name, first_pass);
- to_file = Some(second_file);
- } else {
- let ext_re = Regex::new(r#"(\.(mir|dot|html))$"#).unwrap();
- let cap = ext_re
- .captures_iter(test_name)
- .next()
- .expect("test_name has an invalid extension");
- let extension = cap.get(1).unwrap().as_str();
- expected_file = format!(
- "{}{}{}",
- test_name.trim_end_matches(extension),
- bit_width,
- extension,
- );
- from_file = test_name.to_string();
- assert!(
- test_names.next().is_none(),
- "two mir pass names specified for MIR dump"
+ let files = miropt_test_tools::files_for_miropt_test(
+ &self.testpaths.file,
+ self.config.get_pointer_width(),
+ );
+
+ for miropt_test_tools::MiroptTestFiles { from_file, to_file, expected_file } in files {
+ let dumped_string = if let Some(after) = to_file {
+ self.diff_mir_files(from_file.into(), after.into())
+ } else {
+ let mut output_file = PathBuf::new();
+ output_file.push(self.get_mir_dump_dir());
+ output_file.push(&from_file);
+ debug!(
+ "comparing the contents of: {} with {}",
+ output_file.display(),
+ expected_file.display()
+ );
+ if !output_file.exists() {
+ panic!(
+ "Output file `{}` from test does not exist, available files are in `{}`",
+ output_file.display(),
+ output_file.parent().unwrap().display()
);
- to_file = None;
- };
- if !expected_file.starts_with(&test_crate) {
- expected_file = format!("{}.{}", test_crate, expected_file);
}
- let expected_file = test_dir.join(expected_file);
+ self.check_mir_test_timestamp(&from_file, &output_file);
+ let dumped_string = fs::read_to_string(&output_file).unwrap();
+ self.normalize_output(&dumped_string, &[])
+ };
- let dumped_string = if let Some(after) = to_file {
- self.diff_mir_files(from_file.into(), after.into())
- } else {
- let mut output_file = PathBuf::new();
- output_file.push(self.get_mir_dump_dir());
- output_file.push(&from_file);
- debug!(
- "comparing the contents of: {} with {}",
- output_file.display(),
+ if self.config.bless {
+ let _ = std::fs::remove_file(&expected_file);
+ std::fs::write(expected_file, dumped_string.as_bytes()).unwrap();
+ } else {
+ if !expected_file.exists() {
+ panic!("Output file `{}` from test does not exist", expected_file.display());
+ }
+ let expected_string = fs::read_to_string(&expected_file).unwrap();
+ if dumped_string != expected_string {
+ print!("{}", write_diff(&expected_string, &dumped_string, 3));
+ panic!(
+ "Actual MIR output differs from expected MIR output {}",
expected_file.display()
);
- if !output_file.exists() {
- panic!(
- "Output file `{}` from test does not exist, available files are in `{}`",
- output_file.display(),
- output_file.parent().unwrap().display()
- );
- }
- self.check_mir_test_timestamp(&from_file, &output_file);
- let dumped_string = fs::read_to_string(&output_file).unwrap();
- self.normalize_output(&dumped_string, &[])
- };
-
- if self.config.bless {
- let _ = std::fs::remove_file(&expected_file);
- std::fs::write(expected_file, dumped_string.as_bytes()).unwrap();
- } else {
- if !expected_file.exists() {
- panic!(
- "Output file `{}` from test does not exist",
- expected_file.display()
- );
- }
- let expected_string = fs::read_to_string(&expected_file).unwrap();
- if dumped_string != expected_string {
- print!("{}", write_diff(&expected_string, &dumped_string, 3));
- panic!(
- "Actual MIR output differs from expected MIR output {}",
- expected_file.display()
- );
- }
}
}
}
Yes,
No,
}
+
+enum LinkToAux {
+ Yes,
+ No,
+}
use std::env;
use std::ffi::OsStr;
use std::path::PathBuf;
+use std::process::Command;
use tracing::*;
}
}
}
+
+/// The name of the environment variable that holds dynamic library locations.
+pub fn dylib_env_var() -> &'static str {
+ if cfg!(windows) {
+ "PATH"
+ } else if cfg!(target_os = "macos") {
+ "DYLD_LIBRARY_PATH"
+ } else if cfg!(target_os = "haiku") {
+ "LIBRARY_PATH"
+ } else {
+ "LD_LIBRARY_PATH"
+ }
+}
+
+/// Adds a list of lookup paths to `cmd`'s dynamic library lookup path.
+/// If the dylib_path_var is already set for this cmd, the old value will be overwritten!
+pub fn add_dylib_path(cmd: &mut Command, paths: impl Iterator<Item = impl Into<PathBuf>>) {
+ let path_env = env::var_os(dylib_env_var());
+ let old_paths = path_env.as_ref().map(env::split_paths);
+ let new_paths = paths.map(Into::into).chain(old_paths.into_iter().flatten());
+ cmd.env(dylib_env_var(), env::join_paths(new_paths).unwrap());
+}
branches:
- 'master'
schedule:
- - cron: '5 15 * * *' # At 15:05 UTC every day.
+ - cron: '6 6 * * *' # At 6:06 UTC every day.
env:
CARGO_UNSTABLE_SPARSE_REGISTRY: 'true'
strategy:
fail-fast: false
matrix:
- build: [linux64, macos, win32]
include:
- - build: linux64
- os: ubuntu-latest
+ - os: ubuntu-latest
host_target: x86_64-unknown-linux-gnu
- - build: macos
- os: macos-latest
+ - os: macos-latest
host_target: x86_64-apple-darwin
- - build: win32
- os: windows-latest
+ - os: windows-latest
host_target: i686-pc-windows-msvc
steps:
- uses: actions/checkout@v3
;;
i686-pc-windows-msvc)
MIRI_TEST_TARGET=x86_64-unknown-linux-gnu run_tests
+ MIRI_TEST_TARGET=x86_64-pc-windows-gnu run_tests
;;
*)
echo "FATAL: unknown OS"
}
}
-/// Returns the "default sysroot" that Miri will use for host things if no `--sysroot` flag is set.
-/// Should be a compile-time constant.
-fn host_sysroot() -> Option<String> {
- if option_env!("RUSTC_STAGE").is_some() {
- // This is being built as part of rustc, and gets shipped with rustup.
- // We can rely on the sysroot computation in librustc_session.
- return None;
- }
- // For builds outside rustc, we need to ensure that we got a sysroot
- // that gets used as a default. The sysroot computation in librustc_session would
- // end up somewhere in the build dir (see `get_or_default_sysroot`).
- // Taken from PR <https://github.com/Manishearth/rust-clippy/pull/911>.
- let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME"));
- let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN"));
- Some(match (home, toolchain) {
- (Some(home), Some(toolchain)) => {
- // Check that at runtime, we are still in this toolchain (if there is any toolchain).
- if let Some(toolchain_runtime) =
- env::var_os("RUSTUP_TOOLCHAIN").or_else(|| env::var_os("MULTIRUST_TOOLCHAIN"))
- {
- if toolchain_runtime != toolchain {
- show_error!(
- "This Miri got built with local toolchain `{toolchain}`, but now is being run under a different toolchain. \n\
- Make sure to run Miri in the toolchain it got built with, e.g. via `cargo +{toolchain} miri`."
- )
- }
- }
- format!("{home}/toolchains/{toolchain}")
- }
- _ => option_env!("RUST_SYSROOT")
- .unwrap_or_else(|| {
- show_error!(
- "To build Miri without rustup, set the `RUST_SYSROOT` env var at build time",
- )
- })
- .to_owned(),
- })
-}
-
/// Execute a compiler with the given CLI arguments and callbacks.
fn run_compiler(
mut args: Vec<String>,
target_crate: bool,
callbacks: &mut (dyn rustc_driver::Callbacks + Send),
) -> ! {
- // Make sure we use the right default sysroot. The default sysroot is wrong,
- // because `get_or_default_sysroot` in `librustc_session` bases that on `current_exe`.
- //
- // Make sure we always call `host_sysroot` as that also does some sanity-checks
- // of the environment we were built in and whether it matches what we are running in.
- let host_default_sysroot = host_sysroot();
- // Now see if we even need to set something.
- let sysroot_flag = "--sysroot";
- if !args.iter().any(|e| e == sysroot_flag) {
- // No sysroot was set, let's see if we have a custom default we want to configure.
- let default_sysroot = if target_crate {
+ if target_crate {
+ // Miri needs a custom sysroot for target crates.
+ // If no `--sysroot` is given, the `MIRI_SYSROOT` env var is consulted to find where
+ // that sysroot lives, and that is passed to rustc.
+ let sysroot_flag = "--sysroot";
+ if !args.iter().any(|e| e == sysroot_flag) {
// Using the built-in default here would be plain wrong, so we *require*
// the env var to make sure things make sense.
- Some(env::var("MIRI_SYSROOT").unwrap_or_else(|_| {
+ let miri_sysroot = env::var("MIRI_SYSROOT").unwrap_or_else(|_| {
show_error!(
"Miri was invoked in 'target' mode without `MIRI_SYSROOT` or `--sysroot` being set"
- )
- }))
- } else {
- host_default_sysroot
- };
- if let Some(sysroot) = default_sysroot {
- // We need to overwrite the default that librustc_session would compute.
+ )
+ });
+
args.push(sysroot_flag.to_owned());
- args.push(sysroot);
+ args.push(miri_sysroot);
}
}
#![feature(never_type)]
#![feature(try_blocks)]
#![feature(io_error_more)]
-#![feature(int_log)]
#![feature(variant_count)]
#![feature(yeet_expr)]
#![feature(is_some_and)]
clippy::cast_lossless,
clippy::cast_possible_truncation,
)]
+// Needed for rustdoc from bootstrap (with `-Znormalize-docs`).
+#![recursion_limit = "256"]
extern crate rustc_apfloat;
extern crate rustc_ast;
pub use crate::helpers::{CurrentSpan, EvalContextExt as _};
pub use crate::intptrcast::ProvenanceMode;
pub use crate::machine::{
- AllocExtra, FrameData, MiriInterpCx, MiriInterpCxExt, MiriMachine, MiriMemoryKind, Provenance,
- ProvenanceExtra, PAGE_SIZE, STACK_ADDR, STACK_SIZE,
+ AllocExtra, FrameData, MiriInterpCx, MiriInterpCxExt, MiriMachine, MiriMemoryKind,
+ PrimitiveLayouts, Provenance, ProvenanceExtra, PAGE_SIZE, STACK_ADDR, STACK_SIZE,
};
pub use crate::mono_hash_map::MonoHashMap;
pub use crate::operator::EvalContextExt as _;
pub i8: TyAndLayout<'tcx>,
pub i16: TyAndLayout<'tcx>,
pub i32: TyAndLayout<'tcx>,
+ pub i64: TyAndLayout<'tcx>,
+ pub i128: TyAndLayout<'tcx>,
pub isize: TyAndLayout<'tcx>,
pub u8: TyAndLayout<'tcx>,
pub u16: TyAndLayout<'tcx>,
pub u32: TyAndLayout<'tcx>,
+ pub u64: TyAndLayout<'tcx>,
+ pub u128: TyAndLayout<'tcx>,
pub usize: TyAndLayout<'tcx>,
pub bool: TyAndLayout<'tcx>,
pub mut_raw_ptr: TyAndLayout<'tcx>, // *mut ()
i8: layout_cx.layout_of(tcx.types.i8)?,
i16: layout_cx.layout_of(tcx.types.i16)?,
i32: layout_cx.layout_of(tcx.types.i32)?,
+ i64: layout_cx.layout_of(tcx.types.i64)?,
+ i128: layout_cx.layout_of(tcx.types.i128)?,
isize: layout_cx.layout_of(tcx.types.isize)?,
u8: layout_cx.layout_of(tcx.types.u8)?,
u16: layout_cx.layout_of(tcx.types.u16)?,
u32: layout_cx.layout_of(tcx.types.u32)?,
+ u64: layout_cx.layout_of(tcx.types.u64)?,
+ u128: layout_cx.layout_of(tcx.types.u128)?,
usize: layout_cx.layout_of(tcx.types.usize)?,
bool: layout_cx.layout_of(tcx.types.bool)?,
mut_raw_ptr: layout_cx.layout_of(mut_raw_ptr)?,
const_raw_ptr: layout_cx.layout_of(const_raw_ptr)?,
})
}
+
+ pub fn uint(&self, size: Size) -> Option<TyAndLayout<'tcx>> {
+ match size.bits() {
+ 8 => Some(self.u8),
+ 16 => Some(self.u16),
+ 32 => Some(self.u32),
+ 64 => Some(self.u64),
+ 128 => Some(self.u128),
+ _ => None,
+ }
+ }
+
+ pub fn int(&self, size: Size) -> Option<TyAndLayout<'tcx>> {
+ match size.bits() {
+ 8 => Some(self.i8),
+ 16 => Some(self.i16),
+ 32 => Some(self.i32),
+ 64 => Some(self.i64),
+ 128 => Some(self.i128),
+ _ => None,
+ }
+ }
}
/// The machine itself.
mir,
ty::{self, FloatTy, Ty},
};
-use rustc_target::abi::Integer;
+use rustc_target::abi::{Integer, Size};
use crate::*;
use atomic::EvalContextExt as _;
this.write_bytes_ptr(ptr, iter::repeat(val_byte).take(byte_count.bytes_usize()))?;
}
+ "ptr_mask" => {
+ let [ptr, mask] = check_arg_count(args)?;
+
+ let ptr = this.read_pointer(ptr)?;
+ let mask = this.read_scalar(mask)?.to_machine_usize(this)?;
+
+ let masked_addr = Size::from_bytes(ptr.addr().bytes() & mask);
+
+ this.write_pointer(Pointer::new(ptr.provenance, masked_addr), dest)?;
+ }
+
// Floating-point operations
"fabsf32" => {
let [f] = check_arg_count(args)?;
+use std::time::SystemTime;
+
use crate::concurrency::thread::{MachineCallback, Time};
use crate::*;
-use rustc_target::abi::{Align, Size};
-use std::time::SystemTime;
/// Implementation of the SYS_futex syscall.
/// `args` is the arguments *after* the syscall number.
// The first three arguments (after the syscall number itself) are the same to all futex operations:
// (int *addr, int op, int val).
// We checked above that these definitely exist.
- let addr = this.read_immediate(&args[0])?;
+ let addr = this.read_pointer(&args[0])?;
let op = this.read_scalar(&args[1])?.to_i32()?;
let val = this.read_scalar(&args[2])?.to_i32()?;
let thread = this.get_active_thread();
- let addr_scalar = addr.to_scalar();
- let addr_usize = addr_scalar.to_machine_usize(this)?;
+ // This is a vararg function so we have to bring our own type for this pointer.
+ let addr = MPlaceTy::from_aligned_ptr(addr, this.machine.layouts.i32);
+ let addr_usize = addr.ptr.addr().bytes();
let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?;
let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?;
let timeout_time = if this.ptr_is_null(timeout.ptr)? {
None
} else {
- this.check_no_isolation(
- "`futex` syscall with `op=FUTEX_WAIT` and non-null timeout",
- )?;
+ if op & futex_realtime != 0 {
+ 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 => {
}
})
};
- // Check the pointer for alignment and validity.
- // The API requires `addr` to be a 4-byte aligned pointer, and will
- // use the 4 bytes at the given address as an (atomic) i32.
- this.check_ptr_access_align(
- addr_scalar.to_pointer(this)?,
- Size::from_bytes(4),
- Align::from_bytes(4).unwrap(),
- CheckInAllocMsg::MemoryAccessTest,
- )?;
// There may be a concurrent thread changing the value of addr
// and then invoking the FUTEX_WAKE syscall. It is critical that the
// effects of this and the other thread are correctly observed,
this.atomic_fence(AtomicFenceOrd::SeqCst)?;
// Read an `i32` through the pointer, regardless of any wrapper types.
// It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`.
- let futex_val = this
- .read_scalar_at_offset_atomic(
- &addr.into(),
- 0,
- this.machine.layouts.i32,
- AtomicReadOrd::Relaxed,
- )?
- .to_i32()?;
+ let futex_val = this.read_scalar_atomic(&addr, AtomicReadOrd::Relaxed)?.to_i32()?;
if val == futex_val {
// The value still matches, so we block the thread make it wait for FUTEX_WAKE.
this.block_thread(thread);
}
}
- let dest = dest.clone();
this.register_timeout_callback(
thread,
timeout_time,
- Box::new(Callback { thread, addr_usize, dest }),
+ Box::new(Callback { thread, addr_usize, dest: dest.clone() }),
);
}
} else {
let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
let thread = this.pthread_self()?;
let max_len = this.eval_libc("MAXTHREADNAMESIZE")?.to_machine_usize(this)?;
- this.pthread_setname_np(
+ let res = this.pthread_setname_np(
thread,
this.read_scalar(name)?,
max_len.try_into().unwrap(),
)?;
+ // Contrary to the manpage, `pthread_setname_np` on macOS still
+ // returns an integer indicating success.
+ this.write_scalar(res, dest)?;
}
"pthread_getname_np" => {
let [thread, name, len] =
) -> InterpResult<'tcx> {
let this = self.eval_context_mut();
- this.check_no_isolation("`pthread_cond_timedwait`")?;
-
let id = this.condvar_get_or_create_id(cond_op, CONDVAR_ID_OFFSET)?;
let mutex_id = this.mutex_get_or_create_id(mutex_op, MUTEX_ID_OFFSET)?;
let active_thread = this.get_active_thread();
};
let timeout_time = if clock_id == this.eval_libc_i32("CLOCK_REALTIME")? {
+ this.check_no_isolation("`pthread_cond_timedwait` with `CLOCK_REALTIME`")?;
Time::RealTime(SystemTime::UNIX_EPOCH.checked_add(duration).unwrap())
} else if clock_id == this.eval_libc_i32("CLOCK_MONOTONIC")? {
Time::Monotonic(this.machine.clock.anchor().checked_add(duration).unwrap())
use crate::helpers::check_arg_count;
use crate::shims::windows::handle::{EvalContextExt as _, Handle, PseudoHandle};
+use crate::shims::windows::sync::EvalContextExt as _;
use crate::*;
#[derive(Debug, Copy, Clone)]
pub enum Dlsym {
NtWriteFile,
SetThreadDescription,
+ WaitOnAddress,
+ WakeByAddressSingle,
}
impl Dlsym {
"GetSystemTimePreciseAsFileTime" => None,
"NtWriteFile" => Some(Dlsym::NtWriteFile),
"SetThreadDescription" => Some(Dlsym::SetThreadDescription),
+ "WaitOnAddress" => Some(Dlsym::WaitOnAddress),
+ "WakeByAddressSingle" => Some(Dlsym::WakeByAddressSingle),
_ => throw_unsup_format!("unsupported Windows dlsym: {}", name),
})
}
this.write_null(dest)?;
}
+ Dlsym::WaitOnAddress => {
+ let [ptr_op, compare_op, size_op, timeout_op] = check_arg_count(args)?;
+
+ this.WaitOnAddress(ptr_op, compare_op, size_op, timeout_op, dest)?;
+ }
+ Dlsym::WakeByAddressSingle => {
+ let [ptr_op] = check_arg_count(args)?;
+
+ this.WakeByAddressSingle(ptr_op)?;
+ }
}
trace!("{:?}", this.dump_place(**dest));
+use std::time::Duration;
+
+use rustc_target::abi::Size;
+
use crate::concurrency::init_once::InitOnceStatus;
use crate::concurrency::thread::MachineCallback;
use crate::*;
const INIT_ONCE_ID_OFFSET: u64 = 0;
impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
-
#[allow(non_snake_case)]
pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
fn AcquireSRWLockExclusive(&mut self, lock_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> {
this.eval_windows("c", "TRUE")
}
+
+ 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: &PlaceTy<'tcx, Provenance>,
+ ) -> InterpResult<'tcx> {
+ let this = self.eval_context_mut();
+
+ let ptr = this.read_pointer(ptr_op)?;
+ let compare = this.read_pointer(compare_op)?;
+ let size = this.read_scalar(size_op)?.to_machine_usize(this)?;
+ let timeout_ms = this.read_scalar(timeout_op)?.to_u32()?;
+
+ let thread = this.get_active_thread();
+ let addr = ptr.addr().bytes();
+
+ if size > 8 || !size.is_power_of_two() {
+ let invalid_param = this.eval_windows("c", "ERROR_INVALID_PARAMETER")?;
+ this.set_last_error(invalid_param)?;
+ this.write_scalar(Scalar::from_i32(0), dest)?;
+ return Ok(());
+ };
+ let size = Size::from_bytes(size);
+
+ let timeout_time = if timeout_ms == this.eval_windows("c", "INFINITE")?.to_u32()? {
+ None
+ } else {
+ let duration = Duration::from_millis(timeout_ms.into());
+ Some(Time::Monotonic(this.machine.clock.now().checked_add(duration).unwrap()))
+ };
+
+ // See the Linux futex implementation for why this fence exists.
+ this.atomic_fence(AtomicFenceOrd::SeqCst)?;
+
+ let layout = this.machine.layouts.uint(size).unwrap();
+ let futex_val = this
+ .read_scalar_atomic(&MPlaceTy::from_aligned_ptr(ptr, layout), AtomicReadOrd::Relaxed)?;
+ let compare_val = this.read_scalar(&MPlaceTy::from_aligned_ptr(compare, layout).into())?;
+
+ if futex_val == compare_val {
+ // If the values are the same, we have to block.
+ this.block_thread(thread);
+ this.futex_wait(addr, thread, u32::MAX);
+
+ if let Some(timeout_time) = timeout_time {
+ struct Callback<'tcx> {
+ thread: ThreadId,
+ addr: u64,
+ dest: PlaceTy<'tcx, Provenance>,
+ }
+
+ impl<'tcx> VisitTags for Callback<'tcx> {
+ fn visit_tags(&self, visit: &mut dyn FnMut(SbTag)) {
+ let Callback { thread: _, addr: _, dest } = self;
+ dest.visit_tags(visit);
+ }
+ }
+
+ impl<'mir, 'tcx: 'mir> MachineCallback<'mir, 'tcx> for Callback<'tcx> {
+ fn call(&self, this: &mut MiriInterpCx<'mir, 'tcx>) -> InterpResult<'tcx> {
+ this.unblock_thread(self.thread);
+ this.futex_remove_waiter(self.addr, self.thread);
+ let error_timeout = this.eval_windows("c", "ERROR_TIMEOUT")?;
+ this.set_last_error(error_timeout)?;
+ this.write_scalar(Scalar::from_i32(0), &self.dest)?;
+
+ Ok(())
+ }
+ }
+
+ this.register_timeout_callback(
+ thread,
+ timeout_time,
+ Box::new(Callback { thread, addr, dest: dest.clone() }),
+ );
+ }
+ }
+
+ this.write_scalar(Scalar::from_i32(1), dest)?;
+
+ Ok(())
+ }
+
+ fn WakeByAddressSingle(&mut self, ptr_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> {
+ let this = self.eval_context_mut();
+
+ let ptr = this.read_pointer(ptr_op)?;
+
+ // See the Linux futex implementation for why this fence exists.
+ this.atomic_fence(AtomicFenceOrd::SeqCst)?;
+
+ if let Some(thread) = this.futex_wake(ptr.addr().bytes(), u32::MAX) {
+ this.unblock_thread(thread);
+ this.unregister_timeout_callback_if_exists(thread);
+ }
+
+ Ok(())
+ }
}
layout::{HasParamEnv, LayoutOf},
Ty,
};
-use rustc_span::DUMMY_SP;
use rustc_target::abi::Abi;
use rustc_target::abi::Size;
use smallvec::SmallVec;
let mut kind_str = format!("{kind}");
match kind {
RefKind::Unique { two_phase: false }
- if !ty.is_unpin(this.tcx.at(DUMMY_SP), this.param_env()) =>
+ if !ty.is_unpin(*this.tcx, this.param_env()) =>
{
write!(kind_str, " (!Unpin pointee type {ty})").unwrap()
},
RefKind::Shared
- if !ty.is_freeze(this.tcx.at(DUMMY_SP), this.param_env()) =>
+ if !ty.is_freeze(*this.tcx, this.param_env()) =>
{
write!(kind_str, " (!Freeze pointee type {ty})").unwrap()
},
// There could be existing unique pointers reborrowed from them that should remain valid!
let perm = match kind {
RefKind::Unique { two_phase: false }
- if place.layout.ty.is_unpin(this.tcx.at(DUMMY_SP), this.param_env()) =>
+ if place.layout.ty.is_unpin(*this.tcx, this.param_env()) =>
{
// Only if the type is unpin do we actually enforce uniqueness
Permission::Unique
-//@ignore-target-windows: Concurrency on Windows is not supported yet.
//@compile-flags: -Zmiri-preemption-rate=0
use std::thread;
// windows tls dtors go through libstd right now, thus this test
// cannot pass. When windows tls dtors go through the special magic
// windows linker section, we can run this test on windows again.
-//@ignore-target-windows
+//@ignore-target-windows: no-std not supported on Windows
// Plumbing to let us use `writeln!` to host stderr:
--- /dev/null
+//@ignore-target-windows: No libc on Windows
+//@ignore-target-apple: pthread_condattr_setclock is not supported on MacOS.
+
+/// Test that conditional variable timeouts are working properly
+/// with monotonic clocks even under isolation.
+use std::mem::MaybeUninit;
+use std::time::Instant;
+
+fn test_timed_wait_timeout(clock_id: i32) {
+ unsafe {
+ let mut attr: MaybeUninit<libc::pthread_condattr_t> = MaybeUninit::uninit();
+ assert_eq!(libc::pthread_condattr_init(attr.as_mut_ptr()), 0);
+ assert_eq!(libc::pthread_condattr_setclock(attr.as_mut_ptr(), clock_id), 0);
+
+ let mut cond: MaybeUninit<libc::pthread_cond_t> = MaybeUninit::uninit();
+ assert_eq!(libc::pthread_cond_init(cond.as_mut_ptr(), attr.as_ptr()), 0);
+ assert_eq!(libc::pthread_condattr_destroy(attr.as_mut_ptr()), 0);
+
+ let mut mutex: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER;
+
+ let mut now_mu: MaybeUninit<libc::timespec> = MaybeUninit::uninit();
+ assert_eq!(libc::clock_gettime(clock_id, now_mu.as_mut_ptr()), 0);
+ let now = now_mu.assume_init();
+ // Waiting for a second... mostly because waiting less requires mich more tricky arithmetic.
+ // FIXME: wait less.
+ let timeout = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: now.tv_nsec };
+
+ assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0);
+ let current_time = Instant::now();
+ assert_eq!(
+ libc::pthread_cond_timedwait(cond.as_mut_ptr(), &mut mutex as *mut _, &timeout),
+ libc::ETIMEDOUT
+ );
+ let elapsed_time = current_time.elapsed().as_millis();
+ assert!(900 <= elapsed_time && elapsed_time <= 1300);
+
+ // Test calling `pthread_cond_timedwait` again with an already elapsed timeout.
+ assert_eq!(
+ libc::pthread_cond_timedwait(cond.as_mut_ptr(), &mut mutex as *mut _, &timeout),
+ libc::ETIMEDOUT
+ );
+
+ // Test that invalid nanosecond values (above 10^9 or negative) are rejected with the
+ // correct error code.
+ let invalid_timeout_1 = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: 1_000_000_000 };
+ assert_eq!(
+ libc::pthread_cond_timedwait(
+ cond.as_mut_ptr(),
+ &mut mutex as *mut _,
+ &invalid_timeout_1
+ ),
+ libc::EINVAL
+ );
+ let invalid_timeout_2 = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: -1 };
+ assert_eq!(
+ libc::pthread_cond_timedwait(
+ cond.as_mut_ptr(),
+ &mut mutex as *mut _,
+ &invalid_timeout_2
+ ),
+ libc::EINVAL
+ );
+ // Test that invalid second values (negative) are rejected with the correct error code.
+ let invalid_timeout_3 = libc::timespec { tv_sec: -1, tv_nsec: 0 };
+ assert_eq!(
+ libc::pthread_cond_timedwait(
+ cond.as_mut_ptr(),
+ &mut mutex as *mut _,
+ &invalid_timeout_3
+ ),
+ libc::EINVAL
+ );
+
+ assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0);
+ assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0);
+ assert_eq!(libc::pthread_cond_destroy(cond.as_mut_ptr()), 0);
+ }
+}
+
+fn main() {
+ test_timed_wait_timeout(libc::CLOCK_MONOTONIC);
+}
assert_eq!(e.kind(), ErrorKind::NotFound);
}
-#[cfg(any(target_os = "linux"))]
+#[cfg(target_os = "linux")]
fn test_posix_fadvise() {
use std::convert::TryInto;
use std::io::Write;
assert_eq!(result, 0);
}
-#[cfg(any(target_os = "linux"))]
+#[cfg(target_os = "linux")]
fn test_sync_file_range() {
use std::io::Write;
}
/// Tests whether clock support exists at all
-#[cfg(any(target_os = "linux"))]
+#[cfg(target_os = "linux")]
fn test_clocks() {
let mut tp = std::mem::MaybeUninit::<libc::timespec>::uninit();
let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, tp.as_mut_ptr()) };
}
fn main() {
- #[cfg(any(target_os = "linux"))]
- test_posix_fadvise();
-
test_posix_gettimeofday();
test_posix_mkstemp();
test_posix_realpath_noalloc();
test_posix_realpath_errors();
- #[cfg(any(target_os = "linux"))]
- test_sync_file_range();
-
test_thread_local_errno();
- #[cfg(any(target_os = "linux"))]
- test_clocks();
-
test_isatty();
+
+ #[cfg(target_os = "linux")]
+ {
+ test_posix_fadvise();
+ test_sync_file_range();
+ test_clocks();
+ }
}
//@ignore-target-windows: No libc on Windows
#![feature(cstr_from_bytes_until_nul)]
-use std::ffi::CStr;
+use std::ffi::{CStr, CString};
use std::thread;
fn main() {
test_rwlock_libc_static_initializer();
test_named_thread_truncation();
- #[cfg(any(target_os = "linux"))]
+ #[cfg(target_os = "linux")]
test_mutex_libc_static_initializer_recursive();
}
.chain(std::iter::repeat(" yada").take(100))
.collect::<String>();
+ fn set_thread_name(name: &CStr) -> i32 {
+ #[cfg(target_os = "linux")]
+ return unsafe { libc::pthread_setname_np(libc::pthread_self(), name.as_ptr().cast()) };
+ #[cfg(target_os = "macos")]
+ return unsafe { libc::pthread_setname_np(name.as_ptr().cast()) };
+ }
+
let result = thread::Builder::new().name(long_name.clone()).spawn(move || {
// Rust remembers the full thread name itself.
assert_eq!(thread::current().name(), Some(long_name.as_str()));
// But the system is limited -- make sure we successfully set a truncation.
let mut buf = vec![0u8; long_name.len() + 1];
unsafe {
- libc::pthread_getname_np(libc::pthread_self(), buf.as_mut_ptr().cast(), buf.len());
- }
+ libc::pthread_getname_np(libc::pthread_self(), buf.as_mut_ptr().cast(), buf.len())
+ };
let cstr = CStr::from_bytes_until_nul(&buf).unwrap();
assert!(cstr.to_bytes().len() >= 15); // POSIX seems to promise at least 15 chars
assert!(long_name.as_bytes().starts_with(cstr.to_bytes()));
+
+ // Also test directly calling pthread_setname to check its return value.
+ assert_eq!(set_thread_name(&cstr), 0);
+ // But with a too long name it should fail.
+ assert_ne!(set_thread_name(&CString::new(long_name).unwrap()), 0);
});
result.unwrap().join().unwrap();
}
-//@ignore-target-windows: Channels on Windows are not supported yet.
//@compile-flags: -Zmiri-strict-provenance
use std::sync::mpsc::{channel, sync_channel};
-//@ignore-target-windows: Channels on Windows are not supported yet.
// This specifically tests behavior *without* preemption.
//@compile-flags: -Zmiri-preemption-rate=0
-//@ignore-target-windows: Concurrency on Windows is not supported yet.
//@compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance
use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock};
}
fn main() {
- check_barriers();
- check_conditional_variables_notify_one();
- check_conditional_variables_timed_wait_timeout();
- check_conditional_variables_timed_wait_notimeout();
check_mutex();
check_rwlock_write();
check_rwlock_read_no_deadlock();
check_once();
park_timeout();
park_unpark();
+
+ if !cfg!(windows) {
+ // ignore-target-windows: Condvars on Windows are not supported yet
+ check_barriers();
+ check_conditional_variables_notify_one();
+ check_conditional_variables_timed_wait_timeout();
+ check_conditional_variables_timed_wait_notimeout();
+ } else {
+ // We need to fake the same output...
+ for _ in 0..10 {
+ println!("before wait");
+ }
+ for _ in 0..10 {
+ println!("after wait");
+ }
+ }
}
-//@ignore-target-windows: Concurrency on Windows is not supported yet.
+//@ignore-target-windows: Condvars on Windows are not supported yet.
// We are making scheduler assumptions here.
//@compile-flags: -Zmiri-strict-provenance -Zmiri-preemption-rate=0
--- /dev/null
+//@ignore-target-apple: park_timeout on macOS uses the system clock
+use std::thread;
+use std::time::{Duration, Instant};
+
+fn main() {
+ let start = Instant::now();
+
+ thread::park_timeout(Duration::from_millis(200));
+
+ // Thanks to deterministic execution, this will wiat *exactly* 200ms (rounded to 1ms).
+ assert!((200..201).contains(&start.elapsed().as_millis()));
+}
//@compile-flags: -Coverflow-checks=off
-#![feature(int_log)]
#![allow(arithmetic_overflow)]
pub fn main() {
// windows tls dtors go through libstd right now, thus this test
// cannot pass. When windows tls dtors go through the special magic
// windows linker section, we can run this test on windows again.
-//@ignore-target-windows
+//@ignore-target-windows: no-std not supported on Windows
// Plumbing to let us use `writeln!` to host stdout:
-//@ignore-target-windows
+//@ignore-target-windows: current_exe not supported on Windows
//@only-on-host: the Linux std implementation opens /proc/self/exe, which doesn't work cross-target
//@compile-flags: -Zmiri-disable-isolation
use std::env;
--- /dev/null
+#![feature(ptr_mask)]
+#![feature(strict_provenance)]
+
+fn main() {
+ let v: u32 = 0xABCDABCD;
+ let ptr: *const u32 = &v;
+
+ // u32 is 4 aligned,
+ // so the lower `log2(4) = 2` bits of the address are always 0
+ assert_eq!(ptr.addr() & 0b11, 0);
+
+ let tagged_ptr = ptr.map_addr(|a| a | 0b11);
+ let tag = tagged_ptr.addr() & 0b11;
+ let masked_ptr = tagged_ptr.mask(!0b11);
+
+ assert_eq!(tag, 0b11);
+ assert_eq!(unsafe { *masked_ptr }, 0xABCDABCD);
+}
-//@ignore-target-windows: no threads nor sleep on Windows
//@compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-isolation
use std::sync::{Arc, Mutex};
use std::thread;
-//@ignore-target-windows: Channels on Windows are not supported yet.
-// FIXME: disallow preemption to work around https://github.com/rust-lang/rust/issues/55005
-//@compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0
+//@compile-flags: -Zmiri-ignore-leaks
//! Test that leaking threads works, and that their destructors are not executed.
--- /dev/null
+[package]
+name = "miropt-test-tools"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+regex = "1.0"
--- /dev/null
+use std::fs;
+
+pub struct MiroptTestFiles {
+ pub expected_file: std::path::PathBuf,
+ pub from_file: String,
+ pub to_file: Option<String>,
+}
+
+pub fn files_for_miropt_test(testfile: &std::path::Path, bit_width: u32) -> Vec<MiroptTestFiles> {
+ let mut out = Vec::new();
+ let test_file_contents = fs::read_to_string(&testfile).unwrap();
+
+ let test_dir = testfile.parent().unwrap();
+ let test_crate = testfile.file_stem().unwrap().to_str().unwrap().replace("-", "_");
+
+ let bit_width = if test_file_contents.lines().any(|l| l == "// EMIT_MIR_FOR_EACH_BIT_WIDTH") {
+ format!(".{}bit", bit_width)
+ } else {
+ String::new()
+ };
+
+ for l in test_file_contents.lines() {
+ if l.starts_with("// EMIT_MIR ") {
+ let test_name = l.trim_start_matches("// EMIT_MIR ").trim();
+ let mut test_names = test_name.split(' ');
+ // sometimes we specify two files so that we get a diff between the two files
+ let test_name = test_names.next().unwrap();
+ let mut expected_file;
+ let from_file;
+ let to_file;
+
+ if test_name.ends_with(".diff") {
+ let trimmed = test_name.trim_end_matches(".diff");
+ let test_against = format!("{}.after.mir", trimmed);
+ from_file = format!("{}.before.mir", trimmed);
+ expected_file = format!("{}{}.diff", trimmed, bit_width);
+ assert!(test_names.next().is_none(), "two mir pass names specified for MIR diff");
+ to_file = Some(test_against);
+ } else if let Some(first_pass) = test_names.next() {
+ let second_pass = test_names.next().unwrap();
+ assert!(test_names.next().is_none(), "three mir pass names specified for MIR diff");
+ expected_file =
+ format!("{}{}.{}-{}.diff", test_name, bit_width, first_pass, second_pass);
+ let second_file = format!("{}.{}.mir", test_name, second_pass);
+ from_file = format!("{}.{}.mir", test_name, first_pass);
+ to_file = Some(second_file);
+ } else {
+ let ext_re = regex::Regex::new(r#"(\.(mir|dot|html))$"#).unwrap();
+ let cap = ext_re
+ .captures_iter(test_name)
+ .next()
+ .expect("test_name has an invalid extension");
+ let extension = cap.get(1).unwrap().as_str();
+ expected_file =
+ format!("{}{}{}", test_name.trim_end_matches(extension), bit_width, extension,);
+ from_file = test_name.to_string();
+ assert!(test_names.next().is_none(), "two mir pass names specified for MIR dump");
+ to_file = None;
+ };
+ if !expected_file.starts_with(&test_crate) {
+ expected_file = format!("{}.{}", test_crate, expected_file);
+ }
+ let expected_file = test_dir.join(expected_file);
+
+ out.push(MiroptTestFiles { expected_file, from_file, to_file });
+ }
+ }
+
+ out
+}
[[package]]
name = "lsp-types"
-version = "0.93.1"
+version = "0.93.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3bcfee315dde785ba887edb540b08765fd7df75a7d948844be6bf5712246734"
+checksum = "9be6e9c7e2d18f651974370d7aff703f9513e0df6e464fd795660edc77e6ca51"
dependencies = [
"bitflags",
"serde",
} => {
let mut cmd = Command::new(toolchain::cargo());
cmd.arg(command);
- cmd.args(&["--workspace", "--message-format=json"]);
+ cmd.current_dir(&self.root);
+ cmd.args(&["--workspace", "--message-format=json", "--manifest-path"])
+ .arg(self.root.join("Cargo.toml").as_os_str());
if let Some(target) = target_triple {
cmd.args(&["--target", target.as_str()]);
let mut generic_args: Vec<_> =
std::iter::repeat(None).take(path.segments().len() - 1).collect();
let mut last = GenericArgs::empty();
- let binding =
- AssociatedTypeBinding { name: name![Output], type_ref: Some(orig), bounds: Vec::new() };
+ let binding = AssociatedTypeBinding {
+ name: name![Output],
+ args: None,
+ type_ref: Some(orig),
+ bounds: Vec::new(),
+ };
last.bindings.push(binding);
generic_args.push(Some(Interned::new(last)));
pub struct AssociatedTypeBinding {
/// The name of the associated type.
pub name: Name,
+ /// The generic arguments to the associated type. e.g. For `Trait<Assoc<'a, T> = &'a T>`, this
+ /// would be `['a, T]`.
+ pub args: Option<Interned<GenericArgs>>,
/// The type bound to this associated type (in `Item = T`, this would be the
/// `T`). This can be `None` if there are bounds instead.
pub type_ref: Option<TypeRef>,
ast::GenericArg::AssocTypeArg(assoc_type_arg) => {
if let Some(name_ref) = assoc_type_arg.name_ref() {
let name = name_ref.as_name();
+ let args = assoc_type_arg
+ .generic_arg_list()
+ .and_then(|args| lower_generic_args(lower_ctx, args))
+ .map(Interned::new);
let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it));
let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
l.bounds()
} else {
Vec::new()
};
- bindings.push(AssociatedTypeBinding { name, type_ref, bounds });
+ bindings.push(AssociatedTypeBinding { name, args, type_ref, bounds });
}
}
ast::GenericArg::LifetimeArg(lifetime_arg) => {
let type_ref = TypeRef::from_ast_opt(ctx, ret_type.ty());
bindings.push(AssociatedTypeBinding {
name: name![Output],
+ args: None,
type_ref: Some(type_ref),
bounds: Vec::new(),
});
let type_ref = TypeRef::Tuple(Vec::new());
bindings.push(AssociatedTypeBinding {
name: name![Output],
+ args: None,
type_ref: Some(type_ref),
bounds: Vec::new(),
});
use crate::{
db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
- from_placeholder_idx, to_chalk_trait_id, AdtId, AliasEq, AliasTy, Binders, CallableDefId,
- CallableSig, FnPointer, ImplTraitId, Interner, Lifetime, ProjectionTy, QuantifiedWhereClause,
- Substitution, TraitRef, Ty, TyBuilder, TyKind, WhereClause,
+ from_placeholder_idx, to_chalk_trait_id, utils::generics, AdtId, AliasEq, AliasTy, Binders,
+ CallableDefId, CallableSig, FnPointer, ImplTraitId, Interner, Lifetime, ProjectionTy,
+ QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyKind, WhereClause,
};
pub trait TyExt {
impl ProjectionTyExt for ProjectionTy {
fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef {
- TraitRef {
- trait_id: to_chalk_trait_id(self.trait_(db)),
- substitution: self.substitution.clone(),
- }
+ // FIXME: something like `Split` trait from chalk-solve might be nice.
+ let generics = generics(db.upcast(), from_assoc_type_id(self.associated_ty_id).into());
+ let substitution = Substitution::from_iter(
+ Interner,
+ self.substitution.iter(Interner).skip(generics.len_self()),
+ );
+ TraitRef { trait_id: to_chalk_trait_id(self.trait_(db)), substitution }
}
fn trait_(&self, db: &dyn HirDatabase) -> TraitId {
return write!(f, "{}", TYPE_HINT_TRUNCATION);
}
- let trait_ = f.db.trait_data(self.trait_(f.db));
+ let trait_ref = self.trait_ref(f.db);
write!(f, "<")?;
- self.self_type_parameter(f.db).hir_fmt(f)?;
- write!(f, " as {}", trait_.name)?;
- if self.substitution.len(Interner) > 1 {
+ fmt_trait_ref(&trait_ref, f, true)?;
+ write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
+ let proj_params_count =
+ self.substitution.len(Interner) - trait_ref.substitution.len(Interner);
+ let proj_params = &self.substitution.as_slice(Interner)[..proj_params_count];
+ if !proj_params.is_empty() {
write!(f, "<")?;
- f.write_joined(&self.substitution.as_slice(Interner)[1..], ", ")?;
+ f.write_joined(proj_params, ", ")?;
write!(f, ">")?;
}
- write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
Ok(())
}
}
// Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
if f.display_target.is_test() {
write!(f, "{}::{}", trait_.name, type_alias_data.name)?;
+ // Note that the generic args for the associated type come before those for the
+ // trait (including the self type).
+ // FIXME: reconsider the generic args order upon formatting?
if parameters.len(Interner) > 0 {
write!(f, "<")?;
- f.write_joined(&*parameters.as_slice(Interner), ", ")?;
+ f.write_joined(parameters.as_slice(Interner), ", ")?;
write!(f, ">")?;
}
} else {
angle_open = true;
}
if let AliasTy::Projection(proj) = alias {
- let type_alias =
- f.db.type_alias_data(from_assoc_type_id(proj.associated_ty_id));
- write!(f, "{} = ", type_alias.name)?;
+ let assoc_ty_id = from_assoc_type_id(proj.associated_ty_id);
+ let type_alias = f.db.type_alias_data(assoc_ty_id);
+ write!(f, "{}", type_alias.name)?;
+
+ let proj_arg_count = generics(f.db.upcast(), assoc_ty_id.into()).len_self();
+ if proj_arg_count > 0 {
+ write!(f, "<")?;
+ f.write_joined(
+ &proj.substitution.as_slice(Interner)[..proj_arg_count],
+ ", ",
+ )?;
+ write!(f, ">")?;
+ }
+ write!(f, " = ")?;
}
ty.hir_fmt(f)?;
}
remaining_segments_for_ty,
true,
);
- if let TyKind::Error = ty.kind(Interner) {
+ if ty.is_unknown() {
return None;
}
self.resolve_with_fallback(t, &|_, _, d, _| d)
}
- /// Unify two types and register new trait goals that arise from that.
- pub(crate) fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
+ /// Unify two relatable values (e.g. `Ty`) and register new trait goals that arise from that.
+ pub(crate) fn unify<T: ?Sized + Zip<Interner>>(&mut self, ty1: &T, ty2: &T) -> bool {
let result = match self.try_unify(ty1, ty2) {
Ok(r) => r,
Err(_) => return false,
true
}
- /// Unify two types and return new trait goals arising from it, so the
+ /// Unify two relatable values (e.g. `Ty`) and return new trait goals arising from it, so the
/// caller needs to deal with them.
- pub(crate) fn try_unify<T: Zip<Interner>>(&mut self, t1: &T, t2: &T) -> InferResult<()> {
+ pub(crate) fn try_unify<T: ?Sized + Zip<Interner>>(
+ &mut self,
+ t1: &T,
+ t2: &T,
+ ) -> InferResult<()> {
match self.var_unification_table.relate(
Interner,
&self.db,
pub type VariableKind = chalk_ir::VariableKind<Interner>;
pub type VariableKinds = chalk_ir::VariableKinds<Interner>;
pub type CanonicalVarKinds = chalk_ir::CanonicalVarKinds<Interner>;
+/// Represents generic parameters and an item bound by them. When the item has parent, the binders
+/// also contain the generic parameters for its parent. See chalk's documentation for details.
+///
+/// One thing to keep in mind when working with `Binders` (and `Substitution`s, which represent
+/// generic arguments) in rust-analyzer is that the ordering within *is* significant - the generic
+/// parameters/arguments for an item MUST come before those for its parent. This is to facilitate
+/// the integration with chalk-solve, which mildly puts constraints as such. See #13335 for its
+/// motivation in detail.
pub type Binders<T> = chalk_ir::Binders<T>;
+/// Interned list of generic arguments for an item. When an item has parent, the `Substitution` for
+/// it contains generic arguments for both its parent and itself. See chalk's documentation for
+/// details.
+///
+/// See `Binders` for the constraint on the ordering.
pub type Substitution = chalk_ir::Substitution<Interner>;
pub type GenericArg = chalk_ir::GenericArg<Interner>;
pub type GenericArgData = chalk_ir::GenericArgData<Interner>;
pub type Guidance = chalk_solve::Guidance<Interner>;
pub type WhereClause = chalk_ir::WhereClause<Interner>;
-// FIXME: get rid of this
-pub fn subst_prefix(s: &Substitution, n: usize) -> Substitution {
- Substitution::from_iter(
- Interner,
- s.as_slice(Interner)[..std::cmp::min(s.len(Interner), n)].iter().cloned(),
- )
-}
-
/// Return an index of a parameter in the generic type parameter list by it's id.
pub fn param_idx(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option<usize> {
generics(db.upcast(), id.parent).param_idx(id)
pub fn replace_errors_with_variables<T>(t: &T) -> Canonical<T>
where
T: HasInterner<Interner = Interner> + TypeFoldable<Interner> + Clone,
- T: HasInterner<Interner = Interner>,
{
use chalk_ir::{
fold::{FallibleTypeFolder, TypeSuperFoldable},
.db
.trait_data(trait_ref.hir_trait_id())
.associated_type_by_name(segment.name);
+
match found {
Some(associated_ty) => {
- // FIXME handle type parameters on the segment
+ // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
+ // generic params. It's inefficient to splice the `Substitution`s, so we may want
+ // that method to optionally take parent `Substitution` as we already know them at
+ // this point (`trait_ref.substitution`).
+ let substitution = self.substs_from_path_segment(
+ segment,
+ Some(associated_ty.into()),
+ false,
+ None,
+ );
+ let len_self =
+ generics(self.db.upcast(), associated_ty.into()).len_self();
+ let substitution = Substitution::from_iter(
+ Interner,
+ substitution
+ .iter(Interner)
+ .take(len_self)
+ .chain(trait_ref.substitution.iter(Interner)),
+ );
TyKind::Alias(AliasTy::Projection(ProjectionTy {
associated_ty_id: to_assoc_type_id(associated_ty),
- substitution: trait_ref.substitution,
+ substitution,
}))
.intern(Interner)
}
res,
Some(segment.name.clone()),
move |name, t, associated_ty| {
- if name == segment.name {
- let substs = match self.type_param_mode {
- ParamLoweringMode::Placeholder => {
- // if we're lowering to placeholders, we have to put
- // them in now
- let generics = generics(
- self.db.upcast(),
- self.resolver
- .generic_def()
- .expect("there should be generics if there's a generic param"),
- );
- let s = generics.placeholder_subst(self.db);
- s.apply(t.substitution.clone(), Interner)
- }
- ParamLoweringMode::Variable => t.substitution.clone(),
- };
- // We need to shift in the bound vars, since
- // associated_type_shorthand_candidates does not do that
- let substs = substs.shifted_in_from(Interner, self.in_binders);
- // FIXME handle type parameters on the segment
- Some(
- TyKind::Alias(AliasTy::Projection(ProjectionTy {
- associated_ty_id: to_assoc_type_id(associated_ty),
- substitution: substs,
- }))
- .intern(Interner),
- )
- } else {
- None
+ if name != segment.name {
+ return None;
}
+
+ // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
+ // generic params. It's inefficient to splice the `Substitution`s, so we may want
+ // that method to optionally take parent `Substitution` as we already know them at
+ // this point (`t.substitution`).
+ let substs = self.substs_from_path_segment(
+ segment.clone(),
+ Some(associated_ty.into()),
+ false,
+ None,
+ );
+
+ let len_self = generics(self.db.upcast(), associated_ty.into()).len_self();
+
+ let substs = Substitution::from_iter(
+ Interner,
+ substs.iter(Interner).take(len_self).chain(t.substitution.iter(Interner)),
+ );
+
+ let substs = match self.type_param_mode {
+ ParamLoweringMode::Placeholder => {
+ // if we're lowering to placeholders, we have to put
+ // them in now
+ let generics = generics(self.db.upcast(), def);
+ let s = generics.placeholder_subst(self.db);
+ s.apply(substs, Interner)
+ }
+ ParamLoweringMode::Variable => substs,
+ };
+ // We need to shift in the bound vars, since
+ // associated_type_shorthand_candidates does not do that
+ let substs = substs.shifted_in_from(Interner, self.in_binders);
+ Some(
+ TyKind::Alias(AliasTy::Projection(ProjectionTy {
+ associated_ty_id: to_assoc_type_id(associated_ty),
+ substitution: substs,
+ }))
+ .intern(Interner),
+ )
},
);
// handle defaults. In expression or pattern path segments without
// explicitly specified type arguments, missing type arguments are inferred
// (i.e. defaults aren't used).
- if !infer_args || had_explicit_args {
+ // Generic parameters for associated types are not supposed to have defaults, so we just
+ // ignore them.
+ let is_assoc_ty = if let GenericDefId::TypeAliasId(id) = def {
+ let container = id.lookup(self.db.upcast()).container;
+ matches!(container, ItemContainerId::TraitId(_))
+ } else {
+ false
+ };
+ if !is_assoc_ty && (!infer_args || had_explicit_args) {
let defaults = self.db.generic_defaults(def);
assert_eq!(total_len, defaults.len());
let parent_from = item_len - substs.len();
None => return SmallVec::new(),
Some(t) => t,
};
+ // FIXME: `substs_from_path_segment()` pushes `TyKind::Error` for every parent
+ // generic params. It's inefficient to splice the `Substitution`s, so we may want
+ // that method to optionally take parent `Substitution` as we already know them at
+ // this point (`super_trait_ref.substitution`).
+ let substitution = self.substs_from_path_segment(
+ // FIXME: This is hack. We shouldn't really build `PathSegment` directly.
+ PathSegment { name: &binding.name, args_and_bindings: binding.args.as_deref() },
+ Some(associated_ty.into()),
+ false, // this is not relevant
+ Some(super_trait_ref.self_type_parameter(Interner)),
+ );
+ let self_params = generics(self.db.upcast(), associated_ty.into()).len_self();
+ let substitution = Substitution::from_iter(
+ Interner,
+ substitution
+ .iter(Interner)
+ .take(self_params)
+ .chain(super_trait_ref.substitution.iter(Interner)),
+ );
let projection_ty = ProjectionTy {
associated_ty_id: to_assoc_type_id(associated_ty),
- substitution: super_trait_ref.substitution,
+ substitution,
};
let mut preds: SmallVec<[_; 1]> = SmallVec::with_capacity(
binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
from_foreign_def_id,
infer::{unify::InferenceTable, Adjust, Adjustment, AutoBorrow, OverloadedDeref, PointerCast},
primitive::{FloatTy, IntTy, UintTy},
- static_lifetime,
+ static_lifetime, to_chalk_trait_id,
utils::all_super_traits,
AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner,
- Scalar, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
+ Scalar, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
};
/// This is used as a key for indexing impls.
slot
}
+/// Looks up the impl method that actually runs for the trait method `func`.
+///
+/// Returns `func` if it's not a method defined in a trait or the lookup failed.
pub fn lookup_impl_method(
- self_ty: &Ty,
db: &dyn HirDatabase,
env: Arc<TraitEnvironment>,
- trait_: TraitId,
+ func: FunctionId,
+ fn_subst: Substitution,
+) -> FunctionId {
+ let trait_id = match func.lookup(db.upcast()).container {
+ ItemContainerId::TraitId(id) => id,
+ _ => return func,
+ };
+ let trait_params = db.generic_params(trait_id.into()).type_or_consts.len();
+ let fn_params = fn_subst.len(Interner) - trait_params;
+ let trait_ref = TraitRef {
+ trait_id: to_chalk_trait_id(trait_id),
+ substitution: Substitution::from_iter(Interner, fn_subst.iter(Interner).skip(fn_params)),
+ };
+
+ let name = &db.function_data(func).name;
+ lookup_impl_method_for_trait_ref(trait_ref, db, env, name).unwrap_or(func)
+}
+
+fn lookup_impl_method_for_trait_ref(
+ trait_ref: TraitRef,
+ db: &dyn HirDatabase,
+ env: Arc<TraitEnvironment>,
name: &Name,
) -> Option<FunctionId> {
- let self_ty_fp = TyFingerprint::for_trait_impl(self_ty)?;
- let trait_impls = db.trait_impls_in_deps(env.krate);
- let impls = trait_impls.for_trait_and_self_ty(trait_, self_ty_fp);
- let mut table = InferenceTable::new(db, env.clone());
- find_matching_impl(impls, &mut table, &self_ty).and_then(|data| {
- data.items.iter().find_map(|it| match it {
- AssocItemId::FunctionId(f) => (db.function_data(*f).name == *name).then(|| *f),
- _ => None,
- })
+ let self_ty = trait_ref.self_type_parameter(Interner);
+ let self_ty_fp = TyFingerprint::for_trait_impl(&self_ty)?;
+ let impls = db.trait_impls_in_deps(env.krate);
+ let impls = impls.for_trait_and_self_ty(trait_ref.hir_trait_id(), self_ty_fp);
+
+ let table = InferenceTable::new(db, env);
+
+ let impl_data = find_matching_impl(impls, table, trait_ref)?;
+ impl_data.items.iter().find_map(|it| match it {
+ AssocItemId::FunctionId(f) => (db.function_data(*f).name == *name).then(|| *f),
+ _ => None,
})
}
fn find_matching_impl(
mut impls: impl Iterator<Item = ImplId>,
- table: &mut InferenceTable<'_>,
- self_ty: &Ty,
+ mut table: InferenceTable<'_>,
+ actual_trait_ref: TraitRef,
) -> Option<Arc<ImplData>> {
let db = table.db;
loop {
let impl_ = impls.next()?;
let r = table.run_in_snapshot(|table| {
let impl_data = db.impl_data(impl_);
- let substs =
+ let impl_substs =
TyBuilder::subst_for_def(db, impl_, None).fill_with_inference_vars(table).build();
- let impl_ty = db.impl_self_ty(impl_).substitute(Interner, &substs);
-
- table
- .unify(self_ty, &impl_ty)
- .then(|| {
- let wh_goals =
- crate::chalk_db::convert_where_clauses(db, impl_.into(), &substs)
- .into_iter()
- .map(|b| b.cast(Interner));
+ let trait_ref = db
+ .impl_trait(impl_)
+ .expect("non-trait method in find_matching_impl")
+ .substitute(Interner, &impl_substs);
- let goal = crate::Goal::all(Interner, wh_goals);
+ if !table.unify(&trait_ref, &actual_trait_ref) {
+ return None;
+ }
- table.try_obligation(goal).map(|_| impl_data)
- })
- .flatten()
+ let wcs = crate::chalk_db::convert_where_clauses(db, impl_.into(), &impl_substs)
+ .into_iter()
+ .map(|b| b.cast(Interner));
+ let goal = crate::Goal::all(Interner, wcs);
+ table.try_obligation(goal).map(|_| impl_data)
});
if r.is_some() {
break r;
let expected_receiver =
sig.map(|s| s.params()[0].clone()).substitute(Interner, &fn_subst);
- check_that!(table.unify(&receiver_ty, &expected_receiver));
+ check_that!(table.unify(receiver_ty, &expected_receiver));
}
if let ItemContainerId::ImplId(impl_id) = container {
"#,
);
}
+
+#[test]
+fn projection_type_correct_arguments_order() {
+ check_types_source_code(
+ r#"
+trait Foo<T> {
+ type Assoc<U>;
+}
+fn f<T: Foo<i32>>(a: T::Assoc<usize>) {
+ a;
+ //^ <T as Foo<i32>>::Assoc<usize>
+}
+"#,
+ );
+}
+
+#[test]
+fn generic_associated_type_binding_in_impl_trait() {
+ check_types_source_code(
+ r#"
+//- minicore: sized
+trait Foo<T> {
+ type Assoc<U>;
+}
+fn f(a: impl Foo<i8, Assoc<i16> = i32>) {
+ a;
+ //^ impl Foo<i8, Assoc<i16> = i32>
+}
+ "#,
+ );
+}
"#,
);
}
+
+#[test]
+fn gats_in_path() {
+ check_types(
+ r#"
+//- minicore: deref
+use core::ops::Deref;
+trait PointerFamily {
+ type Pointer<T>: Deref<Target = T>;
+}
+
+fn f<P: PointerFamily>(p: P::Pointer<i32>) {
+ let a = *p;
+ //^ i32
+}
+fn g<P: PointerFamily>(p: <P as PointerFamily>::Pointer<i32>) {
+ let a = *p;
+ //^ i32
+}
+ "#,
+ );
+}
+
+#[test]
+fn gats_with_impl_trait() {
+ // FIXME: the last function (`fn i()`) is not valid Rust as of this writing because you cannot
+ // specify the same associated type multiple times even if their arguments are different (c.f.
+ // `fn h()`, which is valid). Reconsider how to treat these invalid types.
+ check_types(
+ r#"
+//- minicore: deref
+use core::ops::Deref;
+
+trait Trait {
+ type Assoc<T>: Deref<Target = T>;
+ fn get<U>(&self) -> Self::Assoc<U>;
+}
+
+fn f<T>(v: impl Trait) {
+ let a = v.get::<i32>().deref();
+ //^ &i32
+ let a = v.get::<T>().deref();
+ //^ &T
+}
+fn g<'a, T: 'a>(v: impl Trait<Assoc<T> = &'a T>) {
+ let a = v.get::<T>();
+ //^ &T
+ let a = v.get::<()>();
+ //^ Trait::Assoc<(), impl Trait<Assoc<T> = &T>>
+}
+fn h<'a>(v: impl Trait<Assoc<i32> = &'a i32> + Trait<Assoc<i64> = &'a i64>) {
+ let a = v.get::<i32>();
+ //^ &i32
+ let a = v.get::<i64>();
+ //^ &i64
+}
+fn i<'a>(v: impl Trait<Assoc<i32> = &'a i32, Assoc<i64> = &'a i64>) {
+ let a = v.get::<i32>();
+ //^ &i32
+ let a = v.get::<i64>();
+ //^ &i64
+}
+ "#,
+ );
+}
+
+#[test]
+fn gats_with_dyn() {
+ // This test is here to keep track of how we infer things despite traits with GATs being not
+ // object-safe currently.
+ // FIXME: reconsider how to treat these invalid types.
+ check_infer_with_mismatches(
+ r#"
+//- minicore: deref
+use core::ops::Deref;
+
+trait Trait {
+ type Assoc<T>: Deref<Target = T>;
+ fn get<U>(&self) -> Self::Assoc<U>;
+}
+
+fn f<'a>(v: &dyn Trait<Assoc<i32> = &'a i32>) {
+ v.get::<i32>().deref();
+}
+ "#,
+ expect![[r#"
+ 90..94 'self': &Self
+ 127..128 'v': &(dyn Trait<Assoc<i32> = &i32>)
+ 164..195 '{ ...f(); }': ()
+ 170..171 'v': &(dyn Trait<Assoc<i32> = &i32>)
+ 170..184 'v.get::<i32>()': &i32
+ 170..192 'v.get:...eref()': &i32
+ "#]],
+ );
+}
+
+#[test]
+fn gats_in_associated_type_binding() {
+ check_types(
+ r#"
+trait Trait {
+ type Assoc<T>;
+ fn get<U>(&self) -> Self::Assoc<U>;
+}
+
+fn f<T>(t: T)
+where
+ T: Trait<Assoc<i32> = u32>,
+ T: Trait<Assoc<isize> = usize>,
+{
+ let a = t.get::<i32>();
+ //^ u32
+ let a = t.get::<isize>();
+ //^ usize
+ let a = t.get::<()>();
+ //^ Trait::Assoc<(), T>
+}
+
+ "#,
+ );
+}
use crate::{
chalk_db, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, mapping::from_chalk,
- CallableDefId, Interner,
+ CallableDefId, Interner, ProjectionTyExt,
};
use hir_def::{AdtId, ItemContainerId, Lookup, TypeAliasId};
ItemContainerId::TraitId(t) => t,
_ => panic!("associated type not in trait"),
};
- let trait_data = self.0.trait_data(trait_);
- let params = projection_ty.substitution.as_slice(Interner);
- write!(fmt, "<{:?} as {}", ¶ms[0], trait_data.name,)?;
- if params.len() > 1 {
+ let trait_name = &self.0.trait_data(trait_).name;
+ let trait_ref = projection_ty.trait_ref(self.0);
+ let trait_params = trait_ref.substitution.as_slice(Interner);
+ let self_ty = trait_ref.self_type_parameter(Interner);
+ write!(fmt, "<{:?} as {}", self_ty, trait_name)?;
+ if trait_params.len() > 1 {
+ write!(
+ fmt,
+ "<{}>",
+ trait_params[1..].iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))),
+ )?;
+ }
+ write!(fmt, ">::{}", type_alias_data.name)?;
+
+ let proj_params_count = projection_ty.substitution.len(Interner) - trait_params.len();
+ let proj_params = &projection_ty.substitution.as_slice(Interner)[..proj_params_count];
+ if !proj_params.is_empty() {
write!(
fmt,
"<{}>",
- ¶ms[1..].iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))),
+ proj_params.iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))),
)?;
}
- write!(fmt, ">::{}", type_alias_data.name)
+
+ Ok(())
}
pub(crate) fn debug_fn_def_id(
let expr_id = self.expr_id(db, &call.clone().into())?;
let (f_in_trait, substs) = self.infer.as_ref()?.method_resolution(expr_id)?;
- Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, &substs))
+ Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs))
}
pub(crate) fn resolve_await_to_poll(
// HACK: subst for `poll()` coincides with that for `Future` because `poll()` itself
// doesn't have any generic parameters, so we skip building another subst for `poll()`.
let substs = hir_ty::TyBuilder::subst_for_def(db, future_trait, None).push(ty).build();
- Some(self.resolve_impl_method_or_trait_def(db, poll_fn, &substs))
+ Some(self.resolve_impl_method_or_trait_def(db, poll_fn, substs))
}
pub(crate) fn resolve_prefix_expr(
// don't have any generic parameters, so we skip building another subst for the methods.
let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
- Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
+ Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))
}
pub(crate) fn resolve_index_expr(
.push(base_ty.clone())
.push(index_ty.clone())
.build();
- Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
+ Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))
}
pub(crate) fn resolve_bin_expr(
.push(rhs.clone())
.build();
- Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
+ Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))
}
pub(crate) fn resolve_try_expr(
// doesn't have any generic parameters, so we skip building another subst for `branch()`.
let substs = hir_ty::TyBuilder::subst_for_def(db, op_trait, None).push(ty.clone()).build();
- Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
+ Some(self.resolve_impl_method_or_trait_def(db, op_fn, substs))
}
pub(crate) fn resolve_field(
let mut prefer_value_ns = false;
let resolved = (|| {
+ let infer = self.infer.as_deref()?;
if let Some(path_expr) = parent().and_then(ast::PathExpr::cast) {
let expr_id = self.expr_id(db, &path_expr.into())?;
- let infer = self.infer.as_ref()?;
if let Some(assoc) = infer.assoc_resolutions_for_expr(expr_id) {
let assoc = match assoc {
AssocItemId::FunctionId(f_in_trait) => {
None => assoc,
Some(func_ty) => {
if let TyKind::FnDef(_fn_def, subs) = func_ty.kind(Interner) {
- self.resolve_impl_method(db, f_in_trait, subs)
- .map(AssocItemId::FunctionId)
- .unwrap_or(assoc)
+ self.resolve_impl_method_or_trait_def(
+ db,
+ f_in_trait,
+ subs.clone(),
+ )
+ .into()
} else {
assoc
}
prefer_value_ns = true;
} else if let Some(path_pat) = parent().and_then(ast::PathPat::cast) {
let pat_id = self.pat_id(&path_pat.into())?;
- if let Some(assoc) = self.infer.as_ref()?.assoc_resolutions_for_pat(pat_id) {
+ if let Some(assoc) = infer.assoc_resolutions_for_pat(pat_id) {
return Some(PathResolution::Def(AssocItem::from(assoc).into()));
}
if let Some(VariantId::EnumVariantId(variant)) =
- self.infer.as_ref()?.variant_resolution_for_pat(pat_id)
+ infer.variant_resolution_for_pat(pat_id)
{
return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
}
} else if let Some(rec_lit) = parent().and_then(ast::RecordExpr::cast) {
let expr_id = self.expr_id(db, &rec_lit.into())?;
if let Some(VariantId::EnumVariantId(variant)) =
- self.infer.as_ref()?.variant_resolution_for_expr(expr_id)
+ infer.variant_resolution_for_expr(expr_id)
{
return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
}
|| parent().and_then(ast::TupleStructPat::cast).map(ast::Pat::from);
if let Some(pat) = record_pat.or_else(tuple_struct_pat) {
let pat_id = self.pat_id(&pat)?;
- let variant_res_for_pat =
- self.infer.as_ref()?.variant_resolution_for_pat(pat_id);
+ let variant_res_for_pat = infer.variant_resolution_for_pat(pat_id);
if let Some(VariantId::EnumVariantId(variant)) = variant_res_for_pat {
return Some(PathResolution::Def(ModuleDef::Variant(variant.into())));
}
false
}
- fn resolve_impl_method(
+ fn resolve_impl_method_or_trait_def(
&self,
db: &dyn HirDatabase,
func: FunctionId,
- substs: &Substitution,
- ) -> Option<FunctionId> {
- let impled_trait = match func.lookup(db.upcast()).container {
- ItemContainerId::TraitId(trait_id) => trait_id,
- _ => return None,
- };
- if substs.is_empty(Interner) {
- return None;
- }
- let self_ty = substs.at(Interner, 0).ty(Interner)?;
+ substs: Substitution,
+ ) -> FunctionId {
let krate = self.resolver.krate();
- let trait_env = self.resolver.body_owner()?.as_generic_def_id().map_or_else(
+ let owner = match self.resolver.body_owner() {
+ Some(it) => it,
+ None => return func,
+ };
+ let env = owner.as_generic_def_id().map_or_else(
|| Arc::new(hir_ty::TraitEnvironment::empty(krate)),
|d| db.trait_environment(d),
);
-
- let fun_data = db.function_data(func);
- method_resolution::lookup_impl_method(self_ty, db, trait_env, impled_trait, &fun_data.name)
- }
-
- fn resolve_impl_method_or_trait_def(
- &self,
- db: &dyn HirDatabase,
- func: FunctionId,
- substs: &Substitution,
- ) -> FunctionId {
- self.resolve_impl_method(db, func, substs).unwrap_or(func)
+ method_resolution::lookup_impl_method(db, env, func, substs)
}
fn lang_trait_fn(
"#,
);
}
+
+ #[test]
+ fn goto_bin_op_multiple_impl() {
+ check(
+ r#"
+//- minicore: add
+struct S;
+impl core::ops::Add for S {
+ fn add(
+ //^^^
+ ) {}
+}
+impl core::ops::Add<usize> for S {
+ fn add(
+ ) {}
+}
+
+fn f() {
+ S +$0 S
+}
+"#,
+ );
+
+ check(
+ r#"
+//- minicore: add
+struct S;
+impl core::ops::Add for S {
+ fn add(
+ ) {}
+}
+impl core::ops::Add<usize> for S {
+ fn add(
+ //^^^
+ ) {}
+}
+
+fn f() {
+ S +$0 0usize
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn path_call_multiple_trait_impl() {
+ check(
+ r#"
+trait Trait<T> {
+ fn f(_: T);
+}
+impl Trait<i32> for usize {
+ fn f(_: i32) {}
+ //^
+}
+impl Trait<i64> for usize {
+ fn f(_: i64) {}
+}
+fn main() {
+ usize::f$0(0i32);
+}
+"#,
+ );
+
+ check(
+ r#"
+trait Trait<T> {
+ fn f(_: T);
+}
+impl Trait<i32> for usize {
+ fn f(_: i32) {}
+}
+impl Trait<i64> for usize {
+ fn f(_: i64) {}
+ //^
+}
+fn main() {
+ usize::f$0(0i64);
+}
+"#,
+ )
+ }
}
dissimilar = "1.0.4"
itertools = "0.10.5"
scip = "0.1.1"
-lsp-types = { version = "0.93.1", features = ["proposed"] }
+lsp-types = { version = "=0.93.2", features = ["proposed"] }
parking_lot = "0.12.1"
xflags = "0.3.0"
oorandom = "11.1.3"
use lsp_server::Connection;
use project_model::ProjectManifest;
-use rust_analyzer::{cli::flags, config::Config, from_json, lsp_ext::supports_utf8, Result};
+use rust_analyzer::{cli::flags, config::Config, from_json, Result};
use vfs::AbsPathBuf;
#[cfg(all(feature = "mimalloc"))]
name: String::from("rust-analyzer"),
version: Some(rust_analyzer::version().to_string()),
}),
- offset_encoding: if supports_utf8(config.caps()) {
- Some("utf-8".to_string())
- } else {
- None
- },
+ offset_encoding: None,
};
let initialize_result = serde_json::to_value(initialize_result).unwrap();
FileOperationFilter, FileOperationPattern, FileOperationPatternKind,
FileOperationRegistrationOptions, FoldingRangeProviderCapability, HoverProviderCapability,
ImplementationProviderCapability, InlayHintOptions, InlayHintServerCapabilities, OneOf,
- RenameOptions, SaveOptions, SelectionRangeProviderCapability, SemanticTokensFullOptions,
- SemanticTokensLegend, SemanticTokensOptions, ServerCapabilities, SignatureHelpOptions,
- TextDocumentSyncCapability, TextDocumentSyncKind, TextDocumentSyncOptions,
- TypeDefinitionProviderCapability, WorkDoneProgressOptions,
+ PositionEncodingKind, RenameOptions, SaveOptions, SelectionRangeProviderCapability,
+ SemanticTokensFullOptions, SemanticTokensLegend, SemanticTokensOptions, ServerCapabilities,
+ SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind,
+ TextDocumentSyncOptions, TypeDefinitionProviderCapability, WorkDoneProgressOptions,
WorkspaceFileOperationsServerCapabilities, WorkspaceServerCapabilities,
};
use serde_json::json;
use crate::config::{Config, RustfmtConfig};
+use crate::lsp_ext::supports_utf8;
use crate::semantic_tokens;
pub fn server_capabilities(config: &Config) -> ServerCapabilities {
ServerCapabilities {
+ position_encoding: if supports_utf8(config.caps()) {
+ Some(PositionEncodingKind::UTF8)
+ } else {
+ None
+ },
text_document_sync: Some(TextDocumentSyncCapability::Options(TextDocumentSyncOptions {
open_close: Some(true),
change: Some(TextDocumentSyncKind::INCREMENTAL),
load_cargo::{load_workspace, LoadCargoConfig},
Result,
};
-use crate::line_index::{LineEndings, LineIndex, OffsetEncoding};
+use crate::line_index::{LineEndings, LineIndex, PositionEncoding};
use crate::to_proto;
use crate::version::version;
let line_index = self.db.line_index(file_id);
let line_index = LineIndex {
index: line_index,
- encoding: OffsetEncoding::Utf16,
+ encoding: PositionEncoding::Utf16,
endings: LineEndings::Unix,
};
let range_id = self.add_vertex(lsif::Vertex::Range {
let line_index = self.db.line_index(file_id);
let line_index = LineIndex {
index: line_index,
- encoding: OffsetEncoding::Utf16,
+ encoding: PositionEncoding::Utf16,
endings: LineEndings::Unix,
};
let result = folds
time::Instant,
};
-use crate::line_index::{LineEndings, LineIndex, OffsetEncoding};
+use crate::line_index::{LineEndings, LineIndex, PositionEncoding};
use hir::Name;
use ide::{
LineCol, MonikerDescriptorKind, StaticIndex, StaticIndexedFile, TextRange, TokenId,
let line_index = LineIndex {
index: db.line_index(file_id),
- encoding: OffsetEncoding::Utf8,
+ encoding: PositionEncoding::Utf8,
endings: LineEndings::Unix,
};
use crate::{
caps::completion_item_edit_resolve,
diagnostics::DiagnosticsMapConfig,
- line_index::OffsetEncoding,
+ line_index::PositionEncoding,
lsp_ext::{self, supports_utf8, WorkspaceSymbolSearchKind, WorkspaceSymbolSearchScope},
};
.is_some()
}
- pub fn offset_encoding(&self) -> OffsetEncoding {
+ pub fn position_encoding(&self) -> PositionEncoding {
if supports_utf8(&self.caps) {
- OffsetEncoding::Utf8
+ PositionEncoding::Utf8
} else {
- OffsetEncoding::Utf16
+ PositionEncoding::Utf16
}
}
use vfs::{AbsPath, AbsPathBuf};
use crate::{
- global_state::GlobalStateSnapshot, line_index::OffsetEncoding, lsp_ext,
+ global_state::GlobalStateSnapshot, line_index::PositionEncoding, lsp_ext,
to_proto::url_from_abs_path,
};
let uri = url_from_abs_path(&file_name);
let range = {
- let offset_encoding = snap.config.offset_encoding();
+ let position_encoding = snap.config.position_encoding();
lsp_types::Range::new(
- position(&offset_encoding, span, span.line_start, span.column_start),
- position(&offset_encoding, span, span.line_end, span.column_end),
+ position(&position_encoding, span, span.line_start, span.column_start),
+ position(&position_encoding, span, span.line_end, span.column_end),
)
};
lsp_types::Location::new(uri, range)
}
fn position(
- offset_encoding: &OffsetEncoding,
+ position_encoding: &PositionEncoding,
span: &DiagnosticSpan,
line_offset: usize,
column_offset: usize,
};
}
let mut char_offset = 0;
- let len_func = match offset_encoding {
- OffsetEncoding::Utf8 => char::len_utf8,
- OffsetEncoding::Utf16 => char::len_utf16,
+ let len_func = match position_encoding {
+ PositionEncoding::Utf8 => char::len_utf8,
+ PositionEncoding::Utf16 => char::len_utf16,
};
for c in line.text.chars() {
char_offset += 1;
use crate::{
from_json,
global_state::GlobalStateSnapshot,
- line_index::{LineIndex, OffsetEncoding},
+ line_index::{LineIndex, PositionEncoding},
lsp_ext,
lsp_utils::invalid_params_error,
Result,
pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> Result<TextSize> {
let line_col = match line_index.encoding {
- OffsetEncoding::Utf8 => {
+ PositionEncoding::Utf8 => {
LineCol { line: position.line as u32, col: position.character as u32 }
}
- OffsetEncoding::Utf16 => {
+ PositionEncoding::Utf16 => {
let line_col =
LineColUtf16 { line: position.line as u32, col: position.character as u32 };
line_index.index.to_utf8(line_col)
pub(crate) fn file_line_index(&self, file_id: FileId) -> Cancellable<LineIndex> {
let endings = self.vfs.read().1[&file_id];
let index = self.analysis.file_line_index(file_id)?;
- let res = LineIndex { index, endings, encoding: self.config.offset_encoding() };
+ let res = LineIndex { index, endings, encoding: self.config.position_encoding() };
Ok(res)
}
use std::sync::Arc;
-pub enum OffsetEncoding {
+pub enum PositionEncoding {
Utf8,
Utf16,
}
pub(crate) struct LineIndex {
pub(crate) index: Arc<ide::LineIndex>,
pub(crate) endings: LineEndings,
- pub(crate) encoding: OffsetEncoding,
+ pub(crate) encoding: PositionEncoding,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
use std::{collections::HashMap, path::PathBuf};
use lsp_types::request::Request;
+use lsp_types::PositionEncodingKind;
use lsp_types::{
notification::Notification, CodeActionKind, DocumentOnTypeFormattingParams,
PartialResultParams, Position, Range, TextDocumentIdentifier, WorkDoneProgressParams,
}
pub fn supports_utf8(caps: &lsp_types::ClientCapabilities) -> bool {
- caps.offset_encoding.as_deref().unwrap_or_default().iter().any(|it| it == "utf-8")
+ match &caps.general {
+ Some(general) => general
+ .position_encodings
+ .as_deref()
+ .unwrap_or_default()
+ .iter()
+ .any(|it| it == &PositionEncodingKind::UTF8),
+ _ => false,
+ }
}
pub enum MoveItem {}
use crate::{
from_proto,
global_state::GlobalState,
- line_index::{LineEndings, LineIndex, OffsetEncoding},
+ line_index::{LineEndings, LineIndex, PositionEncoding},
LspError,
};
index: Arc::new(ide::LineIndex::new(old_text)),
// We don't care about line endings or offset encoding here.
endings: LineEndings::Unix,
- encoding: OffsetEncoding::Utf16,
+ encoding: PositionEncoding::Utf16,
};
// The changes we got must be applied sequentially, but can cross lines so we
/// Handles a request.
fn on_request(&mut self, req: Request) {
- if self.shutdown_requested {
- self.respond(lsp_server::Response::new_err(
- req.id,
- lsp_server::ErrorCode::InvalidRequest as i32,
- "Shutdown already requested.".to_owned(),
- ));
- return;
- }
+ let mut dispatcher = RequestDispatcher { req: Some(req), global_state: self };
+ dispatcher.on_sync_mut::<lsp_types::request::Shutdown>(|s, ()| {
+ s.shutdown_requested = true;
+ Ok(())
+ });
+
+ if let RequestDispatcher { req: Some(req), global_state: this } = &mut dispatcher {
+ if this.shutdown_requested {
+ this.respond(lsp_server::Response::new_err(
+ req.id.clone(),
+ lsp_server::ErrorCode::InvalidRequest as i32,
+ "Shutdown already requested.".to_owned(),
+ ));
+ return;
+ }
- // Avoid flashing a bunch of unresolved references during initial load.
- if self.workspaces.is_empty() && !self.is_quiescent() {
- self.respond(lsp_server::Response::new_err(
- req.id,
- lsp_server::ErrorCode::ContentModified as i32,
- "waiting for cargo metadata or cargo check".to_owned(),
- ));
- return;
+ // Avoid flashing a bunch of unresolved references during initial load.
+ if this.workspaces.is_empty() && !this.is_quiescent() {
+ this.respond(lsp_server::Response::new_err(
+ req.id.clone(),
+ lsp_server::ErrorCode::ContentModified as i32,
+ "waiting for cargo metadata or cargo check".to_owned(),
+ ));
+ return;
+ }
}
- RequestDispatcher { req: Some(req), global_state: self }
- .on_sync_mut::<lsp_types::request::Shutdown>(|s, ()| {
- s.shutdown_requested = true;
- Ok(())
- })
+ dispatcher
.on_sync_mut::<lsp_ext::ReloadWorkspace>(handlers::handle_workspace_reload)
.on_sync_mut::<lsp_ext::MemoryUsage>(handlers::handle_memory_usage)
.on_sync_mut::<lsp_ext::ShuffleCrateGraph>(handlers::handle_shuffle_crate_graph)
cargo_target_spec::CargoTargetSpec,
config::{CallInfoConfig, Config},
global_state::GlobalStateSnapshot,
- line_index::{LineEndings, LineIndex, OffsetEncoding},
+ line_index::{LineEndings, LineIndex, PositionEncoding},
lsp_ext,
lsp_utils::invalid_params_error,
semantic_tokens, Result,
pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position {
let line_col = line_index.index.line_col(offset);
match line_index.encoding {
- OffsetEncoding::Utf8 => lsp_types::Position::new(line_col.line, line_col.col),
- OffsetEncoding::Utf16 => {
+ PositionEncoding::Utf8 => lsp_types::Position::new(line_col.line, line_col.col),
+ PositionEncoding::Utf16 => {
let line_col = line_index.index.to_utf16(line_col);
lsp_types::Position::new(line_col.line, line_col.col)
}
let line_index = LineIndex {
index: Arc::new(ide::LineIndex::new(text)),
endings: LineEndings::Unix,
- encoding: OffsetEncoding::Utf16,
+ encoding: PositionEncoding::Utf16,
};
let converted: Vec<lsp_types::FoldingRange> =
folds.into_iter().map(|it| folding_range(text, &line_index, true, it)).collect();
Type
AssocTypeArg =
- NameRef GenericParamList? (':' TypeBoundList | ('=' Type | ConstArg))
+ NameRef GenericArgList? (':' TypeBoundList | ('=' Type | ConstArg))
LifetimeArg =
Lifetime
impl ast::HasTypeBounds for AssocTypeArg {}
impl AssocTypeArg {
pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
- pub fn generic_param_list(&self) -> Option<GenericParamList> { support::child(&self.syntax) }
+ pub fn generic_arg_list(&self) -> Option<GenericArgList> { support::child(&self.syntax) }
pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
pub fn const_arg(&self) -> Option<ConstArg> { support::child(&self.syntax) }
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
}
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct GenericParamList {
- pub(crate) syntax: SyntaxNode,
-}
-impl GenericParamList {
- pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
- pub fn generic_params(&self) -> AstChildren<GenericParam> { support::children(&self.syntax) }
- pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
-}
-
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct TypeBoundList {
pub(crate) syntax: SyntaxNode,
pub fn extern_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![extern]) }
}
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct GenericParamList {
+ pub(crate) syntax: SyntaxNode,
+}
+impl GenericParamList {
+ pub fn l_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![<]) }
+ pub fn generic_params(&self) -> AstChildren<GenericParam> { support::children(&self.syntax) }
+ pub fn r_angle_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![>]) }
+}
+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct WhereClause {
pub(crate) syntax: SyntaxNode,
}
fn syntax(&self) -> &SyntaxNode { &self.syntax }
}
-impl AstNode for GenericParamList {
- fn can_cast(kind: SyntaxKind) -> bool { kind == GENERIC_PARAM_LIST }
- fn cast(syntax: SyntaxNode) -> Option<Self> {
- if Self::can_cast(syntax.kind()) {
- Some(Self { syntax })
- } else {
- None
- }
- }
- fn syntax(&self) -> &SyntaxNode { &self.syntax }
-}
impl AstNode for TypeBoundList {
fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_BOUND_LIST }
fn cast(syntax: SyntaxNode) -> Option<Self> {
}
fn syntax(&self) -> &SyntaxNode { &self.syntax }
}
+impl AstNode for GenericParamList {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == GENERIC_PARAM_LIST }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ if Self::can_cast(syntax.kind()) {
+ Some(Self { syntax })
+ } else {
+ None
+ }
+ }
+ fn syntax(&self) -> &SyntaxNode { &self.syntax }
+}
impl AstNode for WhereClause {
fn can_cast(kind: SyntaxKind) -> bool { kind == WHERE_CLAUSE }
fn cast(syntax: SyntaxNode) -> Option<Self> {
std::fmt::Display::fmt(self.syntax(), f)
}
}
-impl std::fmt::Display for GenericParamList {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- std::fmt::Display::fmt(self.syntax(), f)
- }
-}
impl std::fmt::Display for TypeBoundList {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f)
std::fmt::Display::fmt(self.syntax(), f)
}
}
+impl std::fmt::Display for GenericParamList {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
impl std::fmt::Display for WhereClause {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f)
### Configurability
rust-analyzer strives to be as configurable as possible while offering reasonable defaults where no configuration exists yet.
+The rule of thumb is to enable most features by default unless they are buggy or degrade performance too much.
There will always be features that some people find more annoying than helpful, so giving the users the ability to tweak or disable these is a big part of offering a good user experience.
+Enabling them by default is a matter of discoverability, as many users end up don't know about some features even though they are presented in the manual.
Mind the code--architecture gap: at the moment, we are using fewer feature flags than we really should.
### Serialization
<!---
-lsp_ext.rs hash: 7b710095d773b978
+lsp_ext.rs hash: 62068e53ac202dc8
If you need to change the above hash to make the test pass, please check if you
need to adjust this doc as well and ping this issue:
If you want to be notified about the changes to this document, subscribe to [#4604](https://github.com/rust-lang/rust-analyzer/issues/4604).
-## UTF-8 offsets
-
-rust-analyzer supports clangd's extension for opting into UTF-8 as the coordinate space for offsets (by default, LSP uses UTF-16 offsets).
-
-https://clangd.llvm.org/extensions.html#utf-8-offsets
-
## Configuration in `initializationOptions`
**Upstream Issue:** https://github.com/microsoft/language-server-protocol/issues/567
import * as ra from "./lsp_ext";
import * as path from "path";
-import { Ctx, Cmd } from "./ctx";
+import { Ctx, Cmd, CtxInit } from "./ctx";
import { applySnippetWorkspaceEdit, applySnippetTextEdits } from "./snippets";
import { spawnSync } from "child_process";
import { RunnableQuickPick, selectRunnable, createTask, createArgs } from "./run";
export * from "./ast_inspector";
export * from "./run";
-export function analyzerStatus(ctx: Ctx): Cmd {
+export function analyzerStatus(ctx: CtxInit): Cmd {
const tdcp = new (class implements vscode.TextDocumentContentProvider {
readonly uri = vscode.Uri.parse("rust-analyzer-status://status");
readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
async provideTextDocumentContent(_uri: vscode.Uri): Promise<string> {
if (!vscode.window.activeTextEditor) return "";
- const client = await ctx.getClient();
+ const client = ctx.client;
const params: ra.AnalyzerStatusParams = {};
const doc = ctx.activeRustEditor?.document;
};
}
-export function memoryUsage(ctx: Ctx): Cmd {
+export function memoryUsage(ctx: CtxInit): Cmd {
const tdcp = new (class implements vscode.TextDocumentContentProvider {
readonly uri = vscode.Uri.parse("rust-analyzer-memory://memory");
readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
provideTextDocumentContent(_uri: vscode.Uri): vscode.ProviderResult<string> {
if (!vscode.window.activeTextEditor) return "";
- return ctx
- .getClient()
- .then((it) => it.sendRequest(ra.memoryUsage))
- .then((mem: any) => {
- return (
- "Per-query memory usage:\n" + mem + "\n(note: database has been cleared)"
- );
- });
+ return ctx.client.sendRequest(ra.memoryUsage).then((mem: any) => {
+ return "Per-query memory usage:\n" + mem + "\n(note: database has been cleared)";
+ });
}
get onDidChange(): vscode.Event<vscode.Uri> {
};
}
-export function shuffleCrateGraph(ctx: Ctx): Cmd {
+export function shuffleCrateGraph(ctx: CtxInit): Cmd {
return async () => {
- return ctx.getClient().then((it) => it.sendRequest(ra.shuffleCrateGraph));
+ return ctx.client.sendRequest(ra.shuffleCrateGraph);
};
}
-export function matchingBrace(ctx: Ctx): Cmd {
+export function matchingBrace(ctx: CtxInit): Cmd {
return async () => {
const editor = ctx.activeRustEditor;
if (!editor) return;
- const client = await ctx.getClient();
+ const client = ctx.client;
const response = await client.sendRequest(ra.matchingBrace, {
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document),
};
}
-export function joinLines(ctx: Ctx): Cmd {
+export function joinLines(ctx: CtxInit): Cmd {
return async () => {
const editor = ctx.activeRustEditor;
if (!editor) return;
- const client = await ctx.getClient();
+ const client = ctx.client;
const items: lc.TextEdit[] = await client.sendRequest(ra.joinLines, {
ranges: editor.selections.map((it) => client.code2ProtocolConverter.asRange(it)),
};
}
-export function moveItemUp(ctx: Ctx): Cmd {
+export function moveItemUp(ctx: CtxInit): Cmd {
return moveItem(ctx, ra.Direction.Up);
}
-export function moveItemDown(ctx: Ctx): Cmd {
+export function moveItemDown(ctx: CtxInit): Cmd {
return moveItem(ctx, ra.Direction.Down);
}
-export function moveItem(ctx: Ctx, direction: ra.Direction): Cmd {
+export function moveItem(ctx: CtxInit, direction: ra.Direction): Cmd {
return async () => {
const editor = ctx.activeRustEditor;
if (!editor) return;
- const client = await ctx.getClient();
+ const client = ctx.client;
const lcEdits = await client.sendRequest(ra.moveItem, {
range: client.code2ProtocolConverter.asRange(editor.selection),
};
}
-export function onEnter(ctx: Ctx): Cmd {
+export function onEnter(ctx: CtxInit): Cmd {
async function handleKeypress() {
const editor = ctx.activeRustEditor;
if (!editor) return false;
- const client = await ctx.getClient();
+ const client = ctx.client;
const lcEdits = await client
.sendRequest(ra.onEnter, {
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(
};
}
-export function parentModule(ctx: Ctx): Cmd {
+export function parentModule(ctx: CtxInit): Cmd {
return async () => {
const editor = vscode.window.activeTextEditor;
if (!editor) return;
if (!(isRustDocument(editor.document) || isCargoTomlDocument(editor.document))) return;
- const client = await ctx.getClient();
+ const client = ctx.client;
const locations = await client.sendRequest(ra.parentModule, {
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document),
};
}
-export function openCargoToml(ctx: Ctx): Cmd {
+export function openCargoToml(ctx: CtxInit): Cmd {
return async () => {
const editor = ctx.activeRustEditor;
if (!editor) return;
- const client = await ctx.getClient();
+ const client = ctx.client;
const response = await client.sendRequest(ra.openCargoToml, {
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(editor.document),
});
};
}
-export function ssr(ctx: Ctx): Cmd {
+export function ssr(ctx: CtxInit): Cmd {
return async () => {
const editor = vscode.window.activeTextEditor;
if (!editor) return;
- const client = await ctx.getClient();
+ const client = ctx.client;
const position = editor.selection.active;
const selections = editor.selections;
};
}
-export function serverVersion(ctx: Ctx): Cmd {
+export function serverVersion(ctx: CtxInit): Cmd {
return async () => {
if (!ctx.serverPath) {
void vscode.window.showWarningMessage(`rust-analyzer server is not running`);
// Opens the virtual file that will show the syntax tree
//
// The contents of the file come from the `TextDocumentContentProvider`
-export function syntaxTree(ctx: Ctx): Cmd {
+export function syntaxTree(ctx: CtxInit): Cmd {
const tdcp = new (class implements vscode.TextDocumentContentProvider {
readonly uri = vscode.Uri.parse("rust-analyzer-syntax-tree://syntaxtree/tree.rast");
readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
): Promise<string> {
const rustEditor = ctx.activeRustEditor;
if (!rustEditor) return "";
- const client = await ctx.getClient();
+ const client = ctx.client;
// When the range based query is enabled we take the range of the selection
const range =
// Opens the virtual file that will show the HIR of the function containing the cursor position
//
// The contents of the file come from the `TextDocumentContentProvider`
-export function viewHir(ctx: Ctx): Cmd {
+export function viewHir(ctx: CtxInit): Cmd {
const tdcp = new (class implements vscode.TextDocumentContentProvider {
readonly uri = vscode.Uri.parse("rust-analyzer-hir://viewHir/hir.rs");
readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
const rustEditor = ctx.activeRustEditor;
if (!rustEditor) return "";
- const client = await ctx.getClient();
+ const client = ctx.client;
const params = {
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(
rustEditor.document
};
}
-export function viewFileText(ctx: Ctx): Cmd {
+export function viewFileText(ctx: CtxInit): Cmd {
const tdcp = new (class implements vscode.TextDocumentContentProvider {
readonly uri = vscode.Uri.parse("rust-analyzer-file-text://viewFileText/file.rs");
readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
): Promise<string> {
const rustEditor = ctx.activeRustEditor;
if (!rustEditor) return "";
- const client = await ctx.getClient();
+ const client = ctx.client;
const params = client.code2ProtocolConverter.asTextDocumentIdentifier(
rustEditor.document
};
}
-export function viewItemTree(ctx: Ctx): Cmd {
+export function viewItemTree(ctx: CtxInit): Cmd {
const tdcp = new (class implements vscode.TextDocumentContentProvider {
readonly uri = vscode.Uri.parse("rust-analyzer-item-tree://viewItemTree/itemtree.rs");
readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
): Promise<string> {
const rustEditor = ctx.activeRustEditor;
if (!rustEditor) return "";
- const client = await ctx.getClient();
+ const client = ctx.client;
const params = {
textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(
};
}
-function crateGraph(ctx: Ctx, full: boolean): Cmd {
+function crateGraph(ctx: CtxInit, full: boolean): Cmd {
return async () => {
const nodeModulesPath = vscode.Uri.file(path.join(ctx.extensionPath, "node_modules"));
const params = {
full: full,
};
- const client = await ctx.getClient();
+ const client = ctx.client;
const dot = await client.sendRequest(ra.viewCrateGraph, params);
const uri = panel.webview.asWebviewUri(nodeModulesPath);
};
}
-export function viewCrateGraph(ctx: Ctx): Cmd {
+export function viewCrateGraph(ctx: CtxInit): Cmd {
return crateGraph(ctx, false);
}
-export function viewFullCrateGraph(ctx: Ctx): Cmd {
+export function viewFullCrateGraph(ctx: CtxInit): Cmd {
return crateGraph(ctx, true);
}
// Opens the virtual file that will show the syntax tree
//
// The contents of the file come from the `TextDocumentContentProvider`
-export function expandMacro(ctx: Ctx): Cmd {
+export function expandMacro(ctx: CtxInit): Cmd {
function codeFormat(expanded: ra.ExpandedMacro): string {
let result = `// Recursive expansion of ${expanded.name}! macro\n`;
result += "// " + "=".repeat(result.length - 3);
async provideTextDocumentContent(_uri: vscode.Uri): Promise<string> {
const editor = vscode.window.activeTextEditor;
if (!editor) return "";
- const client = await ctx.getClient();
+ const client = ctx.client;
const position = editor.selection.active;
};
}
-export function reloadWorkspace(ctx: Ctx): Cmd {
- return async () => (await ctx.getClient()).sendRequest(ra.reloadWorkspace);
+export function reloadWorkspace(ctx: CtxInit): Cmd {
+ return async () => ctx.client.sendRequest(ra.reloadWorkspace);
}
async function showReferencesImpl(
}
}
-export function showReferences(ctx: Ctx): Cmd {
+export function showReferences(ctx: CtxInit): Cmd {
return async (uri: string, position: lc.Position, locations: lc.Location[]) => {
- await showReferencesImpl(await ctx.getClient(), uri, position, locations);
+ await showReferencesImpl(ctx.client, uri, position, locations);
};
}
-export function applyActionGroup(_ctx: Ctx): Cmd {
+export function applyActionGroup(_ctx: CtxInit): Cmd {
return async (actions: { label: string; arguments: lc.CodeAction }[]) => {
const selectedAction = await vscode.window.showQuickPick(actions);
if (!selectedAction) return;
};
}
-export function gotoLocation(ctx: Ctx): Cmd {
+export function gotoLocation(ctx: CtxInit): Cmd {
return async (locationLink: lc.LocationLink) => {
- const client = await ctx.getClient();
+ const client = ctx.client;
const uri = client.protocol2CodeConverter.asUri(locationLink.targetUri);
let range = client.protocol2CodeConverter.asRange(locationLink.targetSelectionRange);
// collapse the range to a cursor position
};
}
-export function openDocs(ctx: Ctx): Cmd {
+export function openDocs(ctx: CtxInit): Cmd {
return async () => {
const editor = vscode.window.activeTextEditor;
if (!editor) {
return;
}
- const client = await ctx.getClient();
+ const client = ctx.client;
const position = editor.selection.active;
const textDocument = { uri: editor.document.uri.toString() };
};
}
-export function cancelFlycheck(ctx: Ctx): Cmd {
+export function cancelFlycheck(ctx: CtxInit): Cmd {
return async () => {
- const client = await ctx.getClient();
+ const client = ctx.client;
await client.sendRequest(ra.cancelFlycheck);
};
}
-export function resolveCodeAction(ctx: Ctx): Cmd {
+export function resolveCodeAction(ctx: CtxInit): Cmd {
return async (params: lc.CodeAction) => {
- const client = await ctx.getClient();
+ const client = ctx.client;
params.command = undefined;
const item = await client?.sendRequest(lc.CodeActionResolveRequest.type, params);
if (!item?.edit) {
};
}
-export function applySnippetWorkspaceEditCommand(_ctx: Ctx): Cmd {
+export function applySnippetWorkspaceEditCommand(_ctx: CtxInit): Cmd {
return async (edit: vscode.WorkspaceEdit) => {
await applySnippetWorkspaceEdit(edit);
};
}
-export function run(ctx: Ctx): Cmd {
+export function run(ctx: CtxInit): Cmd {
let prevRunnable: RunnableQuickPick | undefined;
return async () => {
};
}
-export function peekTests(ctx: Ctx): Cmd {
+export function peekTests(ctx: CtxInit): Cmd {
return async () => {
const editor = ctx.activeRustEditor;
if (!editor) return;
- const client = await ctx.getClient();
+ const client = ctx.client;
await vscode.window.withProgress(
{
};
}
-export function runSingle(ctx: Ctx): Cmd {
+export function runSingle(ctx: CtxInit): Cmd {
return async (runnable: ra.Runnable) => {
const editor = ctx.activeRustEditor;
if (!editor) return;
};
}
-export function copyRunCommandLine(ctx: Ctx) {
+export function copyRunCommandLine(ctx: CtxInit) {
let prevRunnable: RunnableQuickPick | undefined;
return async () => {
const item = await selectRunnable(ctx, prevRunnable);
};
}
-export function debug(ctx: Ctx): Cmd {
+export function debug(ctx: CtxInit): Cmd {
let prevDebuggee: RunnableQuickPick | undefined;
return async () => {
};
}
-export function debugSingle(ctx: Ctx): Cmd {
+export function debugSingle(ctx: CtxInit): Cmd {
return async (config: ra.Runnable) => {
await startDebugSession(ctx, config);
};
}
-export function newDebugConfig(ctx: Ctx): Cmd {
+export function newDebugConfig(ctx: CtxInit): Cmd {
return async () => {
const item = await selectRunnable(ctx, undefined, true, false);
if (!item) return;
import { Config, substituteVariablesInEnv, substituteVSCodeVariables } from "./config";
import { createClient } from "./client";
-import { isRustEditor, log, RustEditor } from "./util";
+import { isRustDocument, isRustEditor, log, RustEditor } from "./util";
import { ServerStatusParams } from "./lsp_ext";
import { PersistentState } from "./persistent_state";
import { bootstrap } from "./bootstrap";
+// We only support local folders, not eg. Live Share (`vlsl:` scheme), so don't activate if
+// only those are in use. We use "Empty" to represent these scenarios
+// (r-a still somewhat works with Live Share, because commands are tunneled to the host)
+
export type Workspace =
+ | { kind: "Empty" }
| {
kind: "Workspace Folder";
}
files: vscode.TextDocument[];
};
+export function fetchWorkspace(): Workspace {
+ const folders = (vscode.workspace.workspaceFolders || []).filter(
+ (folder) => folder.uri.scheme === "file"
+ );
+ const rustDocuments = vscode.workspace.textDocuments.filter((document) =>
+ isRustDocument(document)
+ );
+
+ return folders.length === 0
+ ? rustDocuments.length === 0
+ ? { kind: "Empty" }
+ : {
+ kind: "Detached Files",
+ files: rustDocuments,
+ }
+ : { kind: "Workspace Folder" };
+}
+
export type CommandFactory = {
- enabled: (ctx: Ctx) => Cmd;
+ enabled: (ctx: CtxInit) => Cmd;
disabled?: (ctx: Ctx) => Cmd;
};
+export type CtxInit = Ctx & {
+ readonly client: lc.LanguageClient;
+};
+
export class Ctx {
readonly statusBar: vscode.StatusBarItem;
readonly config: Config;
+ readonly workspace: Workspace;
- private client: lc.LanguageClient | undefined;
+ private _client: lc.LanguageClient | undefined;
private _serverPath: string | undefined;
private traceOutputChannel: vscode.OutputChannel | undefined;
private outputChannel: vscode.OutputChannel | undefined;
private commandFactories: Record<string, CommandFactory>;
private commandDisposables: Disposable[];
- workspace: Workspace;
+ get client() {
+ return this._client;
+ }
constructor(
readonly extCtx: vscode.ExtensionContext,
- workspace: Workspace,
- commandFactories: Record<string, CommandFactory>
+ commandFactories: Record<string, CommandFactory>,
+ workspace: Workspace
) {
extCtx.subscriptions.push(this);
this.statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
- this.statusBar.text = "rust-analyzer";
- this.statusBar.tooltip = "ready";
- this.statusBar.command = "rust-analyzer.analyzerStatus";
this.statusBar.show();
this.workspace = workspace;
this.clientSubscriptions = [];
this.state = new PersistentState(extCtx.globalState);
this.config = new Config(extCtx);
- this.updateCommands();
+ this.updateCommands("disable");
+ this.setServerStatus({
+ health: "stopped",
+ });
}
dispose() {
this.commandDisposables.forEach((disposable) => disposable.dispose());
}
- clientFetcher() {
- const self = this;
- return {
- get client(): lc.LanguageClient | undefined {
- return self.client;
- },
- };
+ async onWorkspaceFolderChanges() {
+ const workspace = fetchWorkspace();
+ if (workspace.kind === "Detached Files" && this.workspace.kind === "Detached Files") {
+ if (workspace.files !== this.workspace.files) {
+ if (this.client?.isRunning()) {
+ // Ideally we wouldn't need to tear down the server here, but currently detached files
+ // are only specified at server start
+ await this.stopAndDispose();
+ await this.start();
+ }
+ return;
+ }
+ }
+ if (workspace.kind === "Workspace Folder" && this.workspace.kind === "Workspace Folder") {
+ return;
+ }
+ if (workspace.kind === "Empty") {
+ await this.stopAndDispose();
+ return;
+ }
+ if (this.client?.isRunning()) {
+ await this.restart();
+ }
}
- async getClient() {
+ private async getOrCreateClient() {
+ if (this.workspace.kind === "Empty") {
+ return;
+ }
+
if (!this.traceOutputChannel) {
this.traceOutputChannel = vscode.window.createOutputChannel(
"Rust Analyzer Language Server Trace"
this.pushExtCleanup(this.outputChannel);
}
- if (!this.client) {
+ if (!this._client) {
this._serverPath = await bootstrap(this.extCtx, this.config, this.state).catch(
(err) => {
let message = "bootstrap error. ";
const initializationOptions = substituteVSCodeVariables(rawInitializationOptions);
- this.client = await createClient(
+ this._client = await createClient(
this.traceOutputChannel,
this.outputChannel,
initializationOptions,
serverOptions
);
this.pushClientCleanup(
- this.client.onNotification(ra.serverStatus, (params) =>
+ this._client.onNotification(ra.serverStatus, (params) =>
this.setServerStatus(params)
)
);
}
- return this.client;
+ return this._client;
}
- async activate() {
- log.info("Activating language client");
- const client = await this.getClient();
+ async start() {
+ log.info("Starting language client");
+ const client = await this.getOrCreateClient();
+ if (!client) {
+ return;
+ }
await client.start();
this.updateCommands();
- return client;
}
- async deactivate() {
- log.info("Deactivating language client");
- await this.client?.stop();
- this.updateCommands();
+ async restart() {
+ // FIXME: We should re-use the client, that is ctx.deactivate() if none of the configs have changed
+ await this.stopAndDispose();
+ await this.start();
}
async stop() {
+ if (!this._client) {
+ return;
+ }
log.info("Stopping language client");
+ this.updateCommands("disable");
+ await this._client.stop();
+ }
+
+ async stopAndDispose() {
+ if (!this._client) {
+ return;
+ }
+ log.info("Disposing language client");
+ this.updateCommands("disable");
await this.disposeClient();
- this.updateCommands();
}
private async disposeClient() {
this.clientSubscriptions?.forEach((disposable) => disposable.dispose());
this.clientSubscriptions = [];
- await this.client?.dispose();
+ await this._client?.dispose();
this._serverPath = undefined;
- this.client = undefined;
+ this._client = undefined;
}
get activeRustEditor(): RustEditor | undefined {
return this._serverPath;
}
- private updateCommands() {
+ private updateCommands(forceDisable?: "disable") {
this.commandDisposables.forEach((disposable) => disposable.dispose());
this.commandDisposables = [];
- const fetchFactory = (factory: CommandFactory, fullName: string) => {
- return this.client && this.client.isRunning()
- ? factory.enabled
- : factory.disabled ||
- ((_) => () =>
- vscode.window.showErrorMessage(
- `command ${fullName} failed: rust-analyzer server is not running`
- ));
+
+ const clientRunning = (!forceDisable && this._client?.isRunning()) ?? false;
+ const isClientRunning = function (_ctx: Ctx): _ctx is CtxInit {
+ return clientRunning;
};
+
for (const [name, factory] of Object.entries(this.commandFactories)) {
const fullName = `rust-analyzer.${name}`;
- const callback = fetchFactory(factory, fullName)(this);
+ let callback;
+ if (isClientRunning(this)) {
+ // we asserted that `client` is defined
+ callback = factory.enabled(this);
+ } else if (factory.disabled) {
+ callback = factory.disabled(this);
+ } else {
+ callback = () =>
+ vscode.window.showErrorMessage(
+ `command ${fullName} failed: rust-analyzer server is not running`
+ );
+ }
+
this.commandDisposables.push(vscode.commands.registerCommand(fullName, callback));
}
}
- setServerStatus(status: ServerStatusParams) {
+ setServerStatus(status: ServerStatusParams | { health: "stopped" }) {
let icon = "";
const statusBar = this.statusBar;
switch (status.health) {
case "ok":
- statusBar.tooltip = status.message ?? "Ready";
- statusBar.command = undefined;
+ statusBar.tooltip = (status.message ?? "Ready") + "\nClick to stop server.";
+ statusBar.command = "rust-analyzer.stopServer";
statusBar.color = undefined;
statusBar.backgroundColor = undefined;
break;
statusBar.backgroundColor = new vscode.ThemeColor("statusBarItem.errorBackground");
icon = "$(error) ";
break;
+ case "stopped":
+ statusBar.tooltip = "Server is stopped.\nClick to start.";
+ statusBar.command = "rust-analyzer.startServer";
+ statusBar.color = undefined;
+ statusBar.backgroundColor = undefined;
+ statusBar.text = `$(stop-circle) rust-analyzer`;
+ return;
}
if (!status.quiescent) icon = "$(sync~spin) ";
statusBar.text = `${icon}rust-analyzer`;
import * as lc from "vscode-languageclient/node";
import * as commands from "./commands";
-import { CommandFactory, Ctx, Workspace } from "./ctx";
-import { isRustDocument } from "./util";
+import { CommandFactory, Ctx, fetchWorkspace } from "./ctx";
import { activateTaskProvider } from "./tasks";
import { setContextValue } from "./util";
const RUST_PROJECT_CONTEXT_NAME = "inRustProject";
export interface RustAnalyzerExtensionApi {
- // FIXME: this should be non-optional
readonly client?: lc.LanguageClient;
}
.then(() => {}, console.error);
}
- // We only support local folders, not eg. Live Share (`vlsl:` scheme), so don't activate if
- // only those are in use.
- // (r-a still somewhat works with Live Share, because commands are tunneled to the host)
- const folders = (vscode.workspace.workspaceFolders || []).filter(
- (folder) => folder.uri.scheme === "file"
- );
- const rustDocuments = vscode.workspace.textDocuments.filter((document) =>
- isRustDocument(document)
- );
-
- if (folders.length === 0 && rustDocuments.length === 0) {
- // FIXME: Ideally we would choose not to activate at all (and avoid registering
- // non-functional editor commands), but VS Code doesn't seem to have a good way of doing
- // that
- return {};
- }
-
- const workspace: Workspace =
- folders.length === 0
- ? {
- kind: "Detached Files",
- files: rustDocuments,
- }
- : { kind: "Workspace Folder" };
-
- const ctx = new Ctx(context, workspace, createCommands());
+ const ctx = new Ctx(context, createCommands(), fetchWorkspace());
// VS Code doesn't show a notification when an extension fails to activate
// so we do it ourselves.
const api = await activateServer(ctx).catch((err) => {
ctx.pushExtCleanup(activateTaskProvider(ctx.config));
}
+ vscode.workspace.onDidChangeWorkspaceFolders(
+ async (_) => ctx.onWorkspaceFolderChanges(),
+ null,
+ ctx.subscriptions
+ );
vscode.workspace.onDidChangeConfiguration(
async (_) => {
- await ctx
- .clientFetcher()
- .client?.sendNotification("workspace/didChangeConfiguration", { settings: "" });
+ await ctx.client?.sendNotification("workspace/didChangeConfiguration", {
+ settings: "",
+ });
},
null,
ctx.subscriptions
);
- await ctx.activate();
- return ctx.clientFetcher();
+ await ctx.start();
+ return ctx;
}
function createCommands(): Record<string, CommandFactory> {
reload: {
enabled: (ctx) => async () => {
void vscode.window.showInformationMessage("Reloading rust-analyzer...");
- // FIXME: We should re-use the client, that is ctx.deactivate() if none of the configs have changed
- await ctx.stop();
- await ctx.activate();
+ await ctx.restart();
},
disabled: (ctx) => async () => {
void vscode.window.showInformationMessage("Reloading rust-analyzer...");
- await ctx.activate();
+ await ctx.start();
},
},
startServer: {
enabled: (ctx) => async () => {
- await ctx.activate();
+ await ctx.start();
},
disabled: (ctx) => async () => {
- await ctx.activate();
+ await ctx.start();
},
},
stopServer: {
enabled: (ctx) => async () => {
// FIXME: We should re-use the client, that is ctx.deactivate() if none of the configs have changed
- await ctx.stop();
+ await ctx.stopAndDispose();
ctx.setServerStatus({
- health: "ok",
- quiescent: true,
- message: "server is not running",
+ health: "stopped",
});
},
+ disabled: (_) => async () => {},
},
analyzerStatus: { enabled: commands.analyzerStatus },
import * as ra from "./lsp_ext";
import * as tasks from "./tasks";
-import { Ctx } from "./ctx";
+import { CtxInit } from "./ctx";
import { makeDebugConfig } from "./debug";
import { Config, RunnableEnvCfg } from "./config";
];
export async function selectRunnable(
- ctx: Ctx,
+ ctx: CtxInit,
prevRunnable?: RunnableQuickPick,
debuggeeOnly = false,
showButtons: boolean = true
const editor = ctx.activeRustEditor;
if (!editor) return;
- const client = await ctx.getClient();
+ const client = ctx.client;
const textDocument: lc.TextDocumentIdentifier = {
uri: editor.document.uri.toString(),
};
crossbeam-channel = "0.5.6"
[dev-dependencies]
-lsp-types = "0.93.1"
+lsp-types = "=0.93.2"
* `parseQuery` function exported from the search module.
*/
function loadSearchJS(doc_folder, resource_suffix) {
- const searchJs = path.join(doc_folder, "search" + resource_suffix + ".js");
const searchIndexJs = path.join(doc_folder, "search-index" + resource_suffix + ".js");
const searchIndex = require(searchIndexJs);
- const searchModule = require(searchJs);
+
+ const staticFiles = path.join(doc_folder, "static.files");
+ const searchJs = fs.readdirSync(staticFiles).find(
+ f => f.match(/search.*\.js$/));
+ const searchModule = require(path.join(staticFiles, searchJs));
const searchWords = searchModule.initSearch(searchIndex.searchIndex);
return {
false,
None,
false,
+ false,
))
};
Handler::with_emitter(
[dependencies]
cargo_metadata = "0.14"
regex = "1"
+miropt-test-tools = { path = "../miropt-test-tools" }
lazy_static = "1"
walkdir = "2"
+ignore = "0.4.18"
[[bin]]
name = "rust-tidy"
"MIT OR Apache-2.0 OR Zlib", // tinyvec_macros
"MIT OR Zlib OR Apache-2.0", // miniz_oxide
"(MIT OR Apache-2.0) AND Unicode-DFS-2016", // unicode_ident
+ "Unicode-DFS-2016", // tinystr and icu4x
];
/// These are exceptions to Rust's permissive licensing policy, and
"datafrog",
"difference",
"digest",
+ "displaydoc",
"dlmalloc",
"either",
"ena",
pub mod errors;
pub mod extdeps;
pub mod features;
+pub mod mir_opt_tests;
pub mod pal;
pub mod primitive_docs;
pub mod style;
let args: Vec<String> = env::args().skip(1).collect();
let verbose = args.iter().any(|s| *s == "--verbose");
+ let bless = args.iter().any(|s| *s == "--bless");
let bad = std::sync::Arc::new(AtomicBool::new(false));
// Checks over tests.
check!(debug_artifacts, &src_path);
check!(ui_tests, &src_path);
+ check!(mir_opt_tests, &src_path, bless);
// Checks that only make sense for the compiler.
check!(errors, &compiler_path);
--- /dev/null
+//! Tidy check to ensure that mir opt directories do not have stale files or dashes in file names
+
+use std::collections::HashSet;
+use std::path::{Path, PathBuf};
+
+fn check_unused_files(path: &Path, bless: bool, bad: &mut bool) {
+ let mut rs_files = Vec::<PathBuf>::new();
+ let mut output_files = HashSet::<PathBuf>::new();
+ let files = walkdir::WalkDir::new(&path.join("test/mir-opt")).into_iter();
+
+ for file in files.filter_map(Result::ok).filter(|e| e.file_type().is_file()) {
+ let filepath = file.path();
+ if filepath.extension() == Some("rs".as_ref()) {
+ rs_files.push(filepath.to_owned());
+ } else {
+ output_files.insert(filepath.to_owned());
+ }
+ }
+
+ for file in rs_files {
+ for bw in [32, 64] {
+ for output_file in miropt_test_tools::files_for_miropt_test(&file, bw) {
+ output_files.remove(&output_file.expected_file);
+ }
+ }
+ }
+
+ for extra in output_files {
+ if extra.file_name() != Some("README.md".as_ref()) {
+ if !bless {
+ tidy_error!(
+ bad,
+ "the following output file is not associated with any mir-opt test, you can remove it: {}",
+ extra.display()
+ );
+ } else {
+ let _ = std::fs::remove_file(extra);
+ }
+ }
+ }
+}
+
+fn check_dash_files(path: &Path, bless: bool, bad: &mut bool) {
+ for file in walkdir::WalkDir::new(&path.join("test/mir-opt"))
+ .into_iter()
+ .filter_map(Result::ok)
+ .filter(|e| e.file_type().is_file())
+ {
+ let path = file.path();
+ if path.extension() == Some("rs".as_ref()) {
+ if let Some(name) = path.file_name().and_then(|s| s.to_str()) {
+ if name.contains('-') {
+ if !bless {
+ tidy_error!(
+ bad,
+ "mir-opt test files should not have dashes in them: {}",
+ path.display()
+ );
+ } else {
+ let new_name = name.replace('-', "_");
+ let mut new_path = path.to_owned();
+ new_path.set_file_name(new_name);
+ let _ = std::fs::rename(path, new_path);
+ }
+ }
+ }
+ }
+ }
+}
+
+pub fn check(path: &Path, bless: bool, bad: &mut bool) {
+ check_unused_files(path, bless, bad);
+ check_dash_files(path, bless, bad);
+}
//! - the number of entries in each directory must be less than `ENTRY_LIMIT`
//! - there are no stray `.stderr` files
+use ignore::Walk;
+use ignore::WalkBuilder;
use std::fs;
use std::path::Path;
const ENTRY_LIMIT: usize = 1000;
// FIXME: The following limits should be reduced eventually.
-const ROOT_ENTRY_LIMIT: usize = 948;
-const ISSUES_ENTRY_LIMIT: usize = 2117;
+const ROOT_ENTRY_LIMIT: usize = 939;
+const ISSUES_ENTRY_LIMIT: usize = 2105;
fn check_entries(path: &Path, bad: &mut bool) {
- let dirs = walkdir::WalkDir::new(&path.join("test/ui"))
- .into_iter()
- .filter_entry(|e| e.file_type().is_dir());
- for dir in dirs {
- if let Ok(dir) = dir {
- let dir_path = dir.path();
+ for dir in Walk::new(&path.join("test/ui")) {
+ if let Ok(entry) = dir {
+ if entry.file_type().map(|ft| ft.is_dir()).unwrap_or(false) {
+ let dir_path = entry.path();
+ // Use special values for these dirs.
+ let is_root = path.join("test/ui") == dir_path;
+ let is_issues_dir = path.join("test/ui/issues") == dir_path;
+ let limit = if is_root {
+ ROOT_ENTRY_LIMIT
+ } else if is_issues_dir {
+ ISSUES_ENTRY_LIMIT
+ } else {
+ ENTRY_LIMIT
+ };
- // Use special values for these dirs.
- let is_root = path.join("test/ui") == dir_path;
- let is_issues_dir = path.join("test/ui/issues") == dir_path;
- let limit = if is_root {
- ROOT_ENTRY_LIMIT
- } else if is_issues_dir {
- ISSUES_ENTRY_LIMIT
- } else {
- ENTRY_LIMIT
- };
+ let count = WalkBuilder::new(&dir_path)
+ .max_depth(Some(1))
+ .build()
+ .into_iter()
+ .collect::<Vec<_>>()
+ .len()
+ - 1; // remove the dir itself
- let count = std::fs::read_dir(dir_path).unwrap().count();
- if count > limit {
- tidy_error!(
- bad,
- "following path contains more than {} entries, \
- you should move the test to some relevant subdirectory (current: {}): {}",
- limit,
- count,
- dir_path.display()
- );
+ if count > limit {
+ tidy_error!(
+ bad,
+ "following path contains more than {} entries, \
+ you should move the test to some relevant subdirectory (current: {}): {}",
+ limit,
+ count,
+ dir_path.display()
+ );
+ }
}
}
}
"T-*",
"WG-*",
"const-hack",
+ "llvm-main",
"needs-fcp",
"relnotes",
"requires-nightly",
exec "$python" $extra_arg "$xpy" "$@"
fi
done
+
+python=$(bash -c "compgen -c python" | grep '^python[2-3]\.[0-9]\+$' | head -n1)
+if ! [ "$python" = "" ]; then
+ exec "$python" "$xpy" "$@"
+fi
+
echo "$0: error: did not find python installed" >&2
exit 1
$xpy_args += """$arg"""
}
+function Get-Application($app) {
+ return Get-Command $app -ErrorAction SilentlyContinue -CommandType Application
+}
+
foreach ($python in "py", "python3", "python", "python2") {
# NOTE: this only tests that the command exists in PATH, not that it's actually
# executable. The latter is not possible in a portable way, see
# https://github.com/PowerShell/PowerShell/issues/12625.
- if (Get-Command $python -ErrorAction SilentlyContinue) {
+ if (Get-Application $python) {
if ($python -eq "py") {
# Use python3, not python2
$xpy_args = @("-3") + $xpy_args
}
}
+$found = (Get-Application "python*" | Where-Object {$_.name -match '^python[2-3]\.[0-9]+(\.exe)?$'})
+if (($null -ne $found) -and ($found.Length -ge 1)) {
+ $python = $found[0]
+ $process = Start-Process -NoNewWindow -Wait -PassThru $python $xpy_args
+ Exit $process.ExitCode
+}
+
Write-Error "${PSCommandPath}: error: did not find python installed"
Exit 1